diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv')
49 files changed, 2366 insertions, 106 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java index 35c7e5c79..a3b105cfd 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java @@ -3,8 +3,7 @@ package at.gv.egovernment.moa.id.auth.modules.internal; import org.apache.commons.lang3.StringUtils; import at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule; - -import com.datentechnik.process_engine.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; /** * Module descriptor diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java index 8a6c58953..088ec59d4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java @@ -32,14 +32,13 @@ import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.auth.servlet.AuthServlet;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.entrypoints.DispatcherServlet;
+import at.gv.egovernment.moa.id.process.springweb.AbstractSpringWebSupportedTask;
import at.gv.egovernment.moa.id.storage.DBExceptionStoreImpl;
import at.gv.egovernment.moa.id.storage.IExceptionStore;
import at.gv.egovernment.moa.id.util.ServletUtils;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.MiscUtil;
-import com.datentechnik.process_engine.springweb.AbstractSpringWebSupportedTask;
-
/**
* Task based counterpart to {@link AuthServlet}, providing the same utility methods (error handling, parameter parsing
* etc.).</p> The code has been taken from {@link AuthServlet}.
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java index 4af07950b..4bcf717c5 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java @@ -9,6 +9,7 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.BooleanUtils;
import at.gv.egovernment.moa.id.auth.AuthenticationServer;
+import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder;
import at.gv.egovernment.moa.id.auth.builder.InfoboxReadRequestBuilderCertificate;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
@@ -16,13 +17,12 @@ import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
import at.gv.egovernment.moa.id.util.ServletUtils;
import at.gv.egovernment.moa.logging.Logger;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Creates {@code InfoBoxReadRequest} in order to read the subject's certificates.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java index d88042528..08030e623 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java @@ -10,7 +10,6 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.ObjectUtils;
-import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.builder.StartAuthenticationBuilder;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
@@ -18,13 +17,12 @@ import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.auth.servlet.GenerateIFrameTemplateServlet;
import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.MiscUtil;
import at.gv.egovernment.moa.util.StringUtils;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Creates a http form including an embedded {@code InfoBoxReadRequest} for reading the identity link.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java index a661abc95..4e535b83d 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java @@ -28,6 +28,7 @@ import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; import at.gv.egovernment.moa.id.client.SZRGWClientException;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
@@ -35,8 +36,6 @@ import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.DOMUtils;
import at.gv.util.xsd.srzgw.CreateIdentityLinkResponse;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Evaluates the {@code CreateXMLSignatureResponse}, extracts signature and certificate and asks the SZR Gateway for an identity link.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java index 6e4d77b17..6714dfb53 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java @@ -24,6 +24,7 @@ import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.config.ConnectionParameter;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
@@ -33,8 +34,6 @@ import at.gv.egovernment.moa.id.util.client.mis.simple.MISSimpleClient; import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.DOMUtils;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Retrieves a mandate from the online mandate issuing service.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java index d7a95bfcc..d7b35236e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java @@ -14,13 +14,12 @@ import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
import at.gv.egovernment.moa.id.util.ServletUtils;
import at.gv.egovernment.moa.logging.Logger;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Creates {@code CreateXMLSignatureRequest} for auth block signature.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java index 8c59c39ba..060bdf72c 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java @@ -1,5 +1,6 @@ package at.gv.egovernment.moa.id.auth.modules.internal.tasks;
+import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*;
import iaik.pki.PKIException;
import java.io.IOException;
@@ -29,6 +30,7 @@ import at.gv.egovernment.moa.id.config.ConnectionParameter; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
import at.gv.egovernment.moa.id.util.SSLUtils;
@@ -37,9 +39,6 @@ import at.gv.egovernment.moa.id.util.client.mis.simple.MISSimpleClient; import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.DOMUtils;
-import com.datentechnik.process_engine.api.ExecutionContext;
-import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*;
-
/**
* Verifies the signed authentication block (provided as {@code CreateXMLSignatureResponse}).<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java index 7f9fed37a..af0c4c897 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java @@ -20,14 +20,13 @@ import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
import at.gv.egovernment.moa.id.util.ServletUtils;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.spss.util.CertificateUtils;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Parses the certificate from {@code InfoBoxReadResponse} (via POST parameter {@linkplain at.gv.egovernment.moa.id.auth.MOAIDAuthConstants#PARAM_XMLRESPONSE PARAM_XMLRESPONSE}), creates the auth block to be signed and returns a {@code CreateXMLSignatureRequest} for auth block signature.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java index c880570b8..75fdd19aa 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java @@ -11,18 +11,16 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringEscapeUtils;
import at.gv.egovernment.moa.id.auth.AuthenticationServer;
-import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.exception.ParseException;
import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
import at.gv.egovernment.moa.logging.Logger;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Verifies the identity link.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java index 52423166a..55a7907ed 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java @@ -2,9 +2,8 @@ package at.gv.egovernment.moa.id.auth.modules.stork; import org.apache.commons.lang3.StringUtils;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
import at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
/**
* Module descriptor for an auth module providing stork authentication related processes.
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java index 9ffcaaa1e..202e405ef 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java @@ -4,37 +4,22 @@ import iaik.x509.X509Certificate; import java.io.IOException;
import java.io.InputStream;
-import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.security.cert.CertificateException;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import javax.activation.DataSource;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Source;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.stream.StreamSource;
-import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.VelocityEngine;
-import org.opensaml.saml2.core.StatusCode;
import org.xml.sax.SAXException;
-import at.gv.egovernment.moa.id.auth.AuthenticationServer;
-import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.data.IdentityLink;
import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
@@ -44,19 +29,12 @@ import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.ParseException;
import at.gv.egovernment.moa.id.auth.exception.ServiceException;
import at.gv.egovernment.moa.id.auth.modules.internal.tasks.AbstractAuthServletTask;
-import at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet;
import at.gv.egovernment.moa.id.auth.stork.STORKException;
import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor;
-import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
-import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
-import at.gv.egovernment.moa.id.moduls.ModulUtils;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
-import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
-import at.gv.egovernment.moa.id.util.HTTPUtils;
-import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.spss.MOAException;
import at.gv.egovernment.moa.spss.api.SPSSFactory;
@@ -66,25 +44,13 @@ import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureInfo; import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureLocation;
import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest;
import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse;
-import at.gv.egovernment.moa.util.StringUtils;
import at.gv.util.xsd.xmldsig.SignatureType;
import at.gv.util.xsd.xmldsig.X509DataType;
-
-import com.datentechnik.process_engine.api.ExecutionContext;
-
-import eu.stork.oasisdss.api.ApiUtils;
import eu.stork.oasisdss.api.LightweightSourceResolver;
import eu.stork.oasisdss.api.exceptions.ApiUtilsException;
import eu.stork.oasisdss.api.exceptions.UtilsException;
-import eu.stork.oasisdss.profile.SignRequest;
import eu.stork.oasisdss.profile.SignResponse;
import eu.stork.peps.auth.commons.IPersonalAttributeList;
-import eu.stork.peps.auth.commons.PEPSUtil;
-import eu.stork.peps.auth.commons.PersonalAttribute;
-import eu.stork.peps.auth.commons.STORKAuthnRequest;
-import eu.stork.peps.auth.commons.STORKAuthnResponse;
-import eu.stork.peps.auth.engine.STORKSAMLEngine;
-import eu.stork.peps.exceptions.STORKSAMLEngineException;
public abstract class AbstractPepsConnectorWithLocalSigningTask extends AbstractAuthServletTask {
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java index d7480f063..ec7ee04a6 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java @@ -9,7 +9,6 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.StringUtils;
import at.gv.egovernment.moa.id.auth.AuthenticationServer;
-import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.builder.StartAuthenticationBuilder;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
@@ -20,12 +19,11 @@ import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.stork.CPEPS;
import at.gv.egovernment.moa.id.config.stork.STORKConfig;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
import at.gv.egovernment.moa.logging.Logger;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
/**
* Creates a SAML2 STORK authentication request, embeds it in a form (in order to satisfy saml post binging) and returns the form withing the HttpServletResponse.<p/>
* In detail:
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java index d772a50c0..077bb2dee 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java @@ -25,13 +25,11 @@ import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.stork.STORKException;
import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse;
-
-import com.datentechnik.process_engine.api.ExecutionContext;
-
import eu.stork.oasisdss.api.ApiUtils;
import eu.stork.oasisdss.profile.SignResponse;
import eu.stork.peps.auth.commons.IPersonalAttributeList;
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java index 8ed1cf44f..3338804b4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java @@ -32,14 +32,12 @@ import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.HTTPUtils;
import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.StringUtils;
-
-import com.datentechnik.process_engine.api.ExecutionContext;
-
import eu.stork.oasisdss.api.ApiUtils;
import eu.stork.oasisdss.profile.SignRequest;
import eu.stork.oasisdss.profile.SignResponse;
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java index 296132e76..3fb4fb0a9 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java @@ -29,25 +29,6 @@ import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine;
import org.opensaml.saml2.core.StatusCode;
-import com.datentechnik.process_engine.api.ExecutionContext;
-
-import eu.stork.documentservice.DocumentService;
-import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl;
-import eu.stork.oasisdss.api.ApiUtils;
-import eu.stork.oasisdss.api.LightweightSourceResolver;
-import eu.stork.oasisdss.api.exceptions.ApiUtilsException;
-import eu.stork.oasisdss.profile.DocumentType;
-import eu.stork.oasisdss.profile.DocumentWithSignature;
-import eu.stork.oasisdss.profile.SignResponse;
-import eu.stork.peps.auth.commons.IPersonalAttributeList;
-import eu.stork.peps.auth.commons.PEPSUtil;
-import eu.stork.peps.auth.commons.PersonalAttribute;
-import eu.stork.peps.auth.commons.PersonalAttributeList;
-import eu.stork.peps.auth.commons.STORKAttrQueryRequest;
-import eu.stork.peps.auth.commons.STORKAuthnRequest;
-import eu.stork.peps.auth.commons.STORKAuthnResponse;
-import eu.stork.peps.auth.engine.STORKSAMLEngine;
-import eu.stork.peps.exceptions.STORKSAMLEngineException;
import at.gv.egovernment.moa.id.auth.AuthenticationServer;
import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
@@ -61,6 +42,7 @@ import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider;
import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
import at.gv.egovernment.moa.id.moduls.ModulUtils;
+import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage;
import at.gv.egovernment.moa.id.util.HTTPUtils;
@@ -69,6 +51,23 @@ import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.StringUtils;
import at.gv.util.xsd.xmldsig.SignatureType;
import at.gv.util.xsd.xmldsig.X509DataType;
+import eu.stork.documentservice.DocumentService;
+import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl;
+import eu.stork.oasisdss.api.ApiUtils;
+import eu.stork.oasisdss.api.LightweightSourceResolver;
+import eu.stork.oasisdss.api.exceptions.ApiUtilsException;
+import eu.stork.oasisdss.profile.DocumentType;
+import eu.stork.oasisdss.profile.DocumentWithSignature;
+import eu.stork.oasisdss.profile.SignResponse;
+import eu.stork.peps.auth.commons.IPersonalAttributeList;
+import eu.stork.peps.auth.commons.PEPSUtil;
+import eu.stork.peps.auth.commons.PersonalAttribute;
+import eu.stork.peps.auth.commons.PersonalAttributeList;
+import eu.stork.peps.auth.commons.STORKAttrQueryRequest;
+import eu.stork.peps.auth.commons.STORKAuthnRequest;
+import eu.stork.peps.auth.commons.STORKAuthnResponse;
+import eu.stork.peps.auth.engine.STORKSAMLEngine;
+import eu.stork.peps.exceptions.STORKSAMLEngineException;
/**
* Evaluates the SAML response from the C-PEPS and authenticates the user.
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java index 404dc68af..331a7653a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/AuthServlet.java @@ -79,6 +79,7 @@ import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.entrypoints.DispatcherServlet; +import at.gv.egovernment.moa.id.process.ProcessEngine; import at.gv.egovernment.moa.id.storage.DBExceptionStoreImpl; import at.gv.egovernment.moa.id.storage.IExceptionStore; import at.gv.egovernment.moa.id.util.ServletUtils; @@ -86,8 +87,6 @@ import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moa.util.URLDecoder; -import com.datentechnik.process_engine.ProcessEngine; - /** * Base class for MOA-ID Auth Servlets, providing standard error handling and * constant names. diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java index 6e817e2a5..7f53a1a13 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java @@ -42,15 +42,14 @@ import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.moduls.moduleregistration.ModuleRegistration; +import at.gv.egovernment.moa.id.process.ExecutionContextImpl; +import at.gv.egovernment.moa.id.process.ProcessInstance; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.MiscUtil; -import com.datentechnik.process_engine.ExecutionContextImpl; -import com.datentechnik.process_engine.ProcessInstance; -import com.datentechnik.process_engine.api.ExecutionContext; - public class GenerateIFrameTemplateServlet extends AuthServlet { private static final long serialVersionUID = 1L; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java index 01f8e8949..52d1495b4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/ProcessEngineSignalServlet.java @@ -13,10 +13,9 @@ import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils;
+import at.gv.egovernment.moa.id.process.ProcessInstance;
import at.gv.egovernment.moa.id.util.ParamValidatorUtils;
-import com.datentechnik.process_engine.ProcessInstance;
-
/**
* Servlet that resumes a suspended process (in case of asynchronous tasks).
*
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java index 1a0c11aa1..ffb5e3d65 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java @@ -77,6 +77,11 @@ import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.moduls.moduleregistration.ModuleRegistration; +import at.gv.egovernment.moa.id.process.ExecutionContextImpl; +import at.gv.egovernment.moa.id.process.ProcessEngine; +import at.gv.egovernment.moa.id.process.ProcessExecutionException; +import at.gv.egovernment.moa.id.process.ProcessInstance; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; @@ -95,12 +100,6 @@ import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; -import com.datentechnik.process_engine.ExecutionContextImpl; -import com.datentechnik.process_engine.ProcessEngine; -import com.datentechnik.process_engine.ProcessExecutionException; -import com.datentechnik.process_engine.ProcessInstance; -import com.datentechnik.process_engine.api.ExecutionContext; - public class AuthenticationManager implements MOAIDAuthConstants { private static final AuthenticationManager INSTANCE = new AuthenticationManager(); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java index fa0149c17..295a51a24 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java @@ -1,7 +1,7 @@ package at.gv.egovernment.moa.id.moduls.moduleregistration; -import com.datentechnik.process_engine.api.ExecutionContext; -import com.datentechnik.process_engine.model.ProcessDefinition; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.model.ProcessDefinition; /** * Defines the module capabilities. diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java index 7e16cf637..9e06a9ec8 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java @@ -19,9 +19,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.io.Resource; -import com.datentechnik.process_engine.ProcessDefinitionParserException; -import com.datentechnik.process_engine.ProcessEngine; -import com.datentechnik.process_engine.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.ProcessDefinitionParserException; +import at.gv.egovernment.moa.id.process.ProcessEngine; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; /** * This class handles registering modules. The modules are detected either with diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExecutionContextImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExecutionContextImpl.java new file mode 100644 index 000000000..080990f71 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExecutionContextImpl.java @@ -0,0 +1,79 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; + +/** + * ExecutionContext implementation, related to a certain process instance. + * + * @author tknall + * + */ +public class ExecutionContextImpl implements ExecutionContext { + + private static final long serialVersionUID = 1L; + + private Map<String, Serializable> ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>()); + + private String processInstanceId; + + /** + * Creates a new instance. + */ + public ExecutionContextImpl() { + } + + /** + * Creates a new instance and associated it with a certain process instance. + */ + public ExecutionContextImpl(String processInstanceId) { + this.processInstanceId = processInstanceId; + } + + @Override + public void setProcessInstanceId(String processInstanceId) { + this.processInstanceId = processInstanceId; + } + + @Override + public String getProcessInstanceId() { + return processInstanceId; + } + + @Override + public Serializable get(String key) { + return ctxData.get(key); + } + + @Override + public Serializable remove(String key) { + return ctxData.remove(key); + } + + @Override + public void put(String key, Serializable object) { + ctxData.put(key, object); + } + + @Override + public Set<String> keySet() { + return Collections.unmodifiableSet(ctxData.keySet()); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ExecutionContextImpl ["); + builder.append("id=").append(processInstanceId); + builder.append(", variables="); + builder.append(ctxData.keySet()); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExpressionEvaluationContextImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExpressionEvaluationContextImpl.java new file mode 100644 index 000000000..f0d1c861d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExpressionEvaluationContextImpl.java @@ -0,0 +1,44 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluationContext; + +/** + * Context implementation used for expression evaluation only. + * + * @author tknall + * + */ +public class ExpressionEvaluationContextImpl implements ExpressionEvaluationContext { + + private static final long serialVersionUID = 1L; + + private Map<String, Serializable> ctxData; + + /** + * Creates a new instance and initializes it with data from a given process instance. + * + * @param processInstance + * The process instance. + */ + ExpressionEvaluationContextImpl(ProcessInstance processInstance) { + ExecutionContext executionContext = processInstance.getExecutionContext(); + Set<String> keys = executionContext.keySet(); + ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>(keys.size())); + for (String key : keys) { + ctxData.put(key, executionContext.get(key)); + } + } + + @Override + public Map<String, Serializable> getCtx() { + return Collections.unmodifiableMap(ctxData); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParser.java new file mode 100644 index 000000000..162ee624a --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParser.java @@ -0,0 +1,224 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.EventReaderDelegate; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.process.model.EndEvent; +import at.gv.egovernment.moa.id.process.model.ProcessDefinition; +import at.gv.egovernment.moa.id.process.model.ProcessNode; +import at.gv.egovernment.moa.id.process.model.StartEvent; +import at.gv.egovernment.moa.id.process.model.TaskInfo; +import at.gv.egovernment.moa.id.process.model.Transition; + +/** + * Parses an XML representation of a process definition as defined by the respective XML schema. + * <p/ + * The parser is thread-safe. + * @author tknall + * + */ +public class ProcessDefinitionParser { + + private static final String NS = "http://reference.e-government.gv.at/namespace/moa/process/definition/v1"; + + private static Logger log = LoggerFactory.getLogger(ProcessDefinitionParser.class); + + private static class LazyProcessDefinitionSchemaHolder { + private static final Schema PD_SCHEMA_INSTANCE; + static { + try (InputStream in = ProcessDefinitionParser.class.getResourceAsStream("ProcessDefinition.xsd")) { + log.trace("Compiling process definition schema."); + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + // schema is thread-safe + PD_SCHEMA_INSTANCE = factory.newSchema(new StreamSource(in)); + } catch (Exception e) { + throw new RuntimeException("Unable to compile process definition schema.", e); + } + } + } + + /** + * Parses an XML representation of a process definition. The representation is being validated in order to suffice + * the related XML schema. + * + * @param processDefinitionInputStream + * The process definition. + * @return A new process definition. + * @throws ProcessDefinitionParserException + * Thrown in case of error parsing the process definition. + */ + public ProcessDefinition parse(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException { + XMLEventReader reader = null; + final ProcessDefinition pd = new ProcessDefinition(); + log.debug("Parsing and validating process definition."); + try { + + // Standard implementation of XMLInputFactory seems not to be thread-safe + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + reader = inputFactory.createXMLEventReader(processDefinitionInputStream); + + final List<StartElement> transitionElements = new ArrayList<>(); + final List<StartEvent> startEvents = new ArrayList<>(); + + reader = new EventReaderDelegate(reader) { + + @Override + public XMLEvent nextEvent() throws XMLStreamException { + XMLEvent event = super.nextEvent(); + + switch (event.getEventType()) { + case XMLStreamConstants.START_ELEMENT: + StartElement element = event.asStartElement(); + QName qname = element.getName(); + + if (NS.equals(qname.getNamespaceURI())) { + log.trace("Found process description element '{}'.", qname.getLocalPart()); + Attribute id = element.getAttributeByName(new QName("id")); + + switch (qname.getLocalPart()) { + case "ProcessDefinition": + if (id != null) { + pd.setId(id.getValue()); + } + break; + case "StartEvent": + StartEvent startEvent = new StartEvent(); + if (id != null) { + startEvent.setId(id.getValue()); + } + startEvents.add(startEvent); + break; + case "EndEvent": + EndEvent endEvent = new EndEvent(); + if (id != null) { + endEvent.setId(id.getValue()); + pd.getEndEvents().put(id.getValue(), endEvent); + } + break; + case "Transition": + transitionElements.add(element); + break; + case "Task": + TaskInfo taskInfo = new TaskInfo(); + if (id != null) { + taskInfo.setId(id.getValue()); + pd.getTaskInfos().put(id.getValue(), taskInfo); + } + Attribute async = element.getAttributeByName(new QName("async")); + if (async != null) { + taskInfo.setAsync(Boolean.valueOf(async.getValue())); + } + Attribute implementingClass = element.getAttributeByName(new QName("class")); + if (implementingClass != null) { + taskInfo.setTaskImplementingClass(implementingClass.getValue()); + } + break; + } + + } + + break; + } + + return event; + } + + }; + + // validator is not thread-safe + Validator validator = LazyProcessDefinitionSchemaHolder.PD_SCHEMA_INSTANCE.newValidator(); + validator.validate(new StAXSource(reader)); + log.trace("Process definition successfully schema validated."); + + // perform some basic checks + log.trace("Building model and performing some plausibility checks."); + if (startEvents.size() != 1) { + throw new ProcessDefinitionParserException("A ProcessDefinition must contain exactly one single StartEvent."); + } + pd.setStartEvent(startEvents.get(0)); + + // link transitions + Iterator<StartElement> transitions = transitionElements.iterator(); + while (transitions.hasNext()) { + StartElement element = transitions.next(); + Transition transition = new Transition(); + Attribute id = element.getAttributeByName(new QName("id")); + if (id != null) { + transition.setId(id.getValue()); + } + Attribute conditionExpression = element.getAttributeByName(new QName("conditionExpression")); + if (conditionExpression != null) { + transition.setConditionExpression(conditionExpression.getValue()); + } + Attribute from = element.getAttributeByName(new QName("from")); + if (from != null) { + ProcessNode fromNode = pd.getProcessNode(from.getValue()); + if (fromNode == null) { + throw new ProcessDefinitionParserException("Transition's 'from'-attribute refers to a non-existing event or task '" + from.getValue() + '.'); + } + if (fromNode instanceof EndEvent) { + throw new ProcessDefinitionParserException("Transition cannot start from end event."); + } + transition.setFrom(fromNode); + fromNode.getOutgoingTransitions().add(transition); + } + Attribute to = element.getAttributeByName(new QName("to")); + if (to != null) { + ProcessNode toNode = pd.getProcessNode(to.getValue()); + if (toNode == null) { + throw new ProcessDefinitionParserException("Transition's 'to'-attribute refers to a non-existing event or task '" + to.getValue() + '.'); + } + transition.setTo(toNode); + toNode.getIncomingTransitions().add(transition); + } + if (transition.getConditionExpression() == null && Objects.equals(transition.getFrom(), transition.getTo())) { + throw new ProcessDefinitionParserException("Transition's 'from' equals its 'to'. Since no 'conditionExpression' has been set this will cause a loop."); + } + } + log.debug("Process definition '{}' successfully parsed.", pd.getId()); + return pd; + + } catch (ProcessDefinitionParserException e) { + throw e; + } catch (XMLStreamException|IOException e) { + throw new ProcessDefinitionParserException("Unable to read process definition from inputstream.", e); + } catch (SAXException e) { + throw new ProcessDefinitionParserException("Schema validation of process description failed.", e); + } catch (Exception e) { + throw new ProcessDefinitionParserException("Internal error creating process definition from inputstream.", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (XMLStreamException e) { + // error freeing resources + } + } + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParserException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParserException.java new file mode 100644 index 000000000..0c214750d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParserException.java @@ -0,0 +1,35 @@ +package at.gv.egovernment.moa.id.process; + +/** + * Exception thrown in case of error parsing a process definition. + * + * @author tknall + * + */ +public class ProcessDefinitionParserException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Creates a new parser exception providing a {@code message} describing the reason and the {@code cause}. + * + * @param message + * The message. + * @param cause + * The cause. + */ + public ProcessDefinitionParserException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new parser exception providing a {@code message} describing the reason. + * + * @param message + * The message. + */ + public ProcessDefinitionParserException(String message) { + super(message); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java new file mode 100644 index 000000000..2d9dcff8e --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java @@ -0,0 +1,113 @@ +package at.gv.egovernment.moa.id.process; + + +import java.io.InputStream; +import java.io.Serializable; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.model.ProcessDefinition; + +/** + * Process engine providing means for starting and resuming processes. + * + * @author tknall + */ +public interface ProcessEngine { + + /** + * Registers a new process definition. Note that existing definitions with the same identifier will be replaced. + * + * @param processDefinition + * The process definition to be registered. + */ + void registerProcessDefinition(ProcessDefinition processDefinition); + + /** + * Registers a new process definition given as {@link InputStream}. Note that existing definitions with the same identifier will be replaced. + * + * @param processDefinitionInputStream The input stream to the definition to be registered. + * @throws ProcessDefinitionParserException Thrown in case of an error parsing the process definition. + */ + void registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException; + + /** + * Creates a process instance according to the referenced process definition. + * <p/> + * Note that the method returns a process instance which will be needed in order to start a process or to continue + * process execution after asynchronous task execution (refer to {@link #start(ProcessInstance)} and + * {@link #signal(ProcessInstance)} for further information). + * + * @param processDefinitionId + * The identifier of the respective process definition. + * @param executionContext The execution context (may be {@code null}). + * @return The newly created process instance (never {@code null}). + * @throws ProcessExecutionException + * Thrown in case of error, e.g. when a {@code processDefinitionId} is referenced that does not exist. + */ + ProcessInstance createProcessInstance(String processDefinitionId, ExecutionContext executionContext) throws ProcessExecutionException; + + /** + * Creates a process instance according to the referenced process definition. + * <p/> + * Note that the method returns a process instance which will be needed in order to start a process or to continue + * process execution after asynchronous task execution (refer to {@link #start(ProcessInstance)} and + * {@link #signal(ProcessInstance)} for further information). + * + * @param processDefinitionId + * The identifier of the respective process definition. + * @return The newly created process instance (never {@code null}). + * @throws ProcessExecutionException + * Thrown in case of error, e.g. when a {@code processDefinitionId} is referenced that does not exist. + */ + ProcessInstance createProcessInstance(String processDefinitionId) throws ProcessExecutionException; + + /** + * Returns the process instance with a given {@code processInstanceId}. + * + * @param processInstanceId + * The process instance id. + * @return The process instance (never {@code null}). + * @throws IllegalArgumentException + * In case the process instance does not/no longer exist. + */ + ProcessInstance getProcessInstance(String processInstanceId); + + /** + * Starts the process using the given {@code processInstance}. + * + * @param processInstance + * The process instance. + * @throws ProcessExecutionException + * Thrown in case of error. + */ + void start(ProcessInstance processInstance) throws ProcessExecutionException; + + /** + * Resumes process execution after an asynchronous task has been executed. + * + * @param processInstance + * The process instance. + * @throws ProcessExecutionException + * Thrown in case of error. + */ + void signal(ProcessInstance processInstance) throws ProcessExecutionException; + + /** + * Performs cleanup, removing all process instances that have not been used for a certain time. + * + * @see #setProcessInstanceMaxIdleTimeSeconds(long) + */ + void cleanup(); + + /** + * Returns the first process instance with a process context containing some {@code value} stored under key {@code key}. + * + * @param key + * The key. + * @param value + * The value that needs to match. + * @return The process instance or {@code null} in case no process instance was found. + */ + ProcessInstance findProcessInstanceWith(String key, Serializable value); + +}
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java new file mode 100644 index 000000000..3ba8fb9ed --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java @@ -0,0 +1,304 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.InputStream; +import java.io.Serializable; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluationContext; +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluator; +import at.gv.egovernment.moa.id.process.api.Task; +import at.gv.egovernment.moa.id.process.model.EndEvent; +import at.gv.egovernment.moa.id.process.model.ProcessDefinition; +import at.gv.egovernment.moa.id.process.model.ProcessNode; +import at.gv.egovernment.moa.id.process.model.StartEvent; +import at.gv.egovernment.moa.id.process.model.TaskInfo; +import at.gv.egovernment.moa.id.process.model.Transition; + +/** + * Process engine implementation allowing starting and continuing processes as well as providing means for cleanup actions. + * @author tknall + * + */ +public class ProcessEngineImpl implements ProcessEngine { + + private Logger log = LoggerFactory.getLogger(getClass()); + + private ProcessDefinitionParser pdp = new ProcessDefinitionParser(); + + private Map<String, ProcessDefinition> processDefinitions = new ConcurrentHashMap<String, ProcessDefinition>(); + private Map<String, ProcessInstance> processInstances = new ConcurrentHashMap<String, ProcessInstance>(); + + private final static String MDC_CTX_PI_NAME = "processInstanceId"; + private final static String MDC_CTX_TASK_NAME = "taskId"; + + private static final long DEFAULT_PROCESS_INSTANCE_MAX_AGE_SECONDS = 3600; + private long processInstanceIdleTimeSeconds = DEFAULT_PROCESS_INSTANCE_MAX_AGE_SECONDS; + private ExpressionEvaluator transitionConditionExpressionEvaluator; + + @Override + public void registerProcessDefinition(ProcessDefinition processDefinition) { + log.info("Registering process definition '{}'.", processDefinition.getId()); + processDefinitions.put(processDefinition.getId(), processDefinition); + } + + @Override + public void registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException{ + registerProcessDefinition(pdp.parse(processDefinitionInputStream)); + } + + /** + * Sets the process definitions. + * + * @param processDefinitions + * The process definitions. + * @throws IllegalArgumentException + * In case the process definitions contain definitions with the same identifier. + */ + public void setProcessDefinitions(Iterable<ProcessDefinition> processDefinitions) { + this.processDefinitions.clear(); + for (ProcessDefinition pd : processDefinitions) { + if (this.processDefinitions.containsKey(pd.getId())) { + throw new IllegalArgumentException("Duplicate process definition identifier '" + pd.getId() + "'."); + } + registerProcessDefinition(pd); + } + } + + /** + * Defines the time frame in seconds an idle process instance will be managed by the process engine. A process + * instance with an idle time larger than the given time will be removed. + * <p/> + * Note that {@link #cleanup()} needs to be called in order to remove expired process instances. + * + * @param processInstanceMaxIdleTimeSeconds + * The maximum idle time in seconds. + */ + public void setProcessInstanceMaxIdleTimeSeconds(long processInstanceMaxIdleTimeSeconds) { + this.processInstanceIdleTimeSeconds = processInstanceMaxIdleTimeSeconds; + } + + /** + * Sets an expression evaluator that should be used to process transition condition expressions. + * @param transitionConditionExpressionEvaluator The expression evaluator. + */ + public void setTransitionConditionExpressionEvaluator( + ExpressionEvaluator transitionConditionExpressionEvaluator) { + this.transitionConditionExpressionEvaluator = transitionConditionExpressionEvaluator; + } + + + @Override + public ProcessInstance createProcessInstance(String processDefinitionId, ExecutionContext executionContext) throws ProcessExecutionException { + // look for respective process definition + ProcessDefinition pd = processDefinitions.get(processDefinitionId); + if (pd == null) { + throw new ProcessExecutionException("Unable to find process definition for process '" + processDefinitionId + "'."); + } + // create and keep process instance + ProcessInstance pi = new ProcessInstance(pd, executionContext); + log.info("Creating process instance from process definition '{}': {}", processDefinitionId, pi.getId()); + processInstances.put(pi.getId(), pi); + return pi; + } + + @Override + public ProcessInstance createProcessInstance(String processDefinitionId) throws ProcessExecutionException { + return createProcessInstance(processDefinitionId, null); + } + + @Override + public void start(ProcessInstance pi) throws ProcessExecutionException { + MDC.put(MDC_CTX_PI_NAME, pi.getId()); + try { + if (!ProcessInstanceState.NOT_STARTED.equals(pi.getState())) { + throw new ProcessExecutionException("Process instance '" + pi.getId() + "' has already been started (current state is " + pi.getState() + ")."); + } + log.info("Starting process instance '{}'.", pi.getId()); + // execute process + pi.setState(ProcessInstanceState.STARTED); + execute(pi); + } finally { + MDC.remove(MDC_CTX_PI_NAME); + } + } + + @Override + public void signal(ProcessInstance pi) throws ProcessExecutionException { + MDC.put(MDC_CTX_PI_NAME, pi.getId()); + try { + if (!ProcessInstanceState.SUSPENDED.equals(pi.getState())) { + throw new ProcessExecutionException("Process instance '" + pi.getId() + "' has not been suspended (current state is " + pi.getState() + ")."); + } + log.info("Waking up process instance '{}'.", pi.getId()); + pi.setState(ProcessInstanceState.STARTED); + execute(pi); + } finally { + MDC.remove(MDC_CTX_PI_NAME); + } + } + + @Override + public synchronized void cleanup() { + log.trace("Cleanup job started."); + Iterator<Entry<String, ProcessInstance>> it = processInstances.entrySet().iterator(); + while (it.hasNext()) { + Entry<String, ProcessInstance> entry = it.next(); + ProcessInstance pi = entry.getValue(); + log.trace("Checking process instance {}.", pi); + long ageMillis = new Date().getTime() - pi.getLru().getTime(); + if (ageMillis > processInstanceIdleTimeSeconds * 1000) { + log.info("Removing process instance '{}'.", pi.getId()); + processInstances.remove(entry.getKey()); + } + } + log.trace("Cleanup job completed."); + } + + /** + * Instantates a task implementation given by a {@link TaskInfo}. + * @param ti The task info. + * @return A Task implementation or {@code null} if the task info does not reference any task implementing classes. + * @throws ProcessExecutionException Thrown in case of error (when the referenced class does not implement {@link Task} for instance). + */ + private Task createTaskInstance(TaskInfo ti) throws ProcessExecutionException { + String clazz = StringUtils.trimToNull(ti.getTaskImplementingClass()); + Task task = null; + + if (clazz != null) { + log.debug("Instantiating task implementing class '{}'.", clazz); + Class<?> instanceClass = null; + try { + instanceClass = Class.forName(clazz, true, Thread.currentThread().getContextClassLoader()); + } catch (Exception e) { + throw new ProcessExecutionException("Unable to get class '" + clazz + "' associated with task '" + ti.getId() + "' .", e); + } + if (!Task.class.isAssignableFrom(instanceClass)) { + throw new ProcessExecutionException("Class '" + clazz + "' associated with task '" + ti.getId() + "' is not assignable to " + Task.class.getName() + "."); + } + try { + task = (Task) instanceClass.newInstance(); + } catch (Exception e) { + throw new ProcessExecutionException("Unable to instantiate class '" + clazz + "' associated with task '" + ti.getId() + "' .", e); + } + } + + return task; + } + + /** + * Starts/executes a given process instance. + * @param pi The process instance. + * @throws ProcessExecutionException Thrown in case of error. + */ + private void execute(final ProcessInstance pi) throws ProcessExecutionException { + if (ProcessInstanceState.ENDED.equals(pi.getState())) { + throw new ProcessExecutionException("Process for instance '" + pi.getId() + "' has already been ended."); + } + ProcessDefinition pd = pi.getProcessDefinition(); + ProcessNode processNode = pd.getProcessNode(pi.getNextId()); + log.debug("Processing node '{}'.", processNode.getId()); + + // distinguish process node types StartEvent, TaskInfo and EndEvent + + if (processNode instanceof TaskInfo) { + // TaskInfo types need to be executed + TaskInfo ti = (TaskInfo) processNode; + MDC.put(MDC_CTX_TASK_NAME, ti.getId()); + try { + log.info("Processing task '{}'.", ti.getId()); + Task task = createTaskInstance(ti); + if (task != null) { + try { + log.info("Executing task implementation for task '{}'.", ti.getId()); + log.debug("Execution context before task execution: {}", pi.getExecutionContext().keySet()); + task.execute(pi.getExecutionContext()); + log.info("Returned from execution of task '{}'.", ti.getId()); + log.debug("Execution context after task execution: {}", pi.getExecutionContext().keySet()); + } catch (Throwable t) { + throw new ProcessExecutionException("Error executing task '" + ti.getId() + "'.", t); + } + } else { + log.debug("No task implementing class set."); + } + } finally { + MDC.remove(MDC_CTX_TASK_NAME); + } + + } else if (processNode instanceof EndEvent) { + log.info("Finishing process instance '{}'.", pi.getId()); + processInstances.remove(pi.getId()); + pi.setState(ProcessInstanceState.ENDED); + log.debug("Final process context: {}", pi.getExecutionContext().keySet()); + return; + } + + final ExpressionEvaluationContext expressionContext = new ExpressionEvaluationContextImpl(pi); + + // traverse pointer + Transition t = CollectionUtils.find(processNode.getOutgoingTransitions(), new Predicate<Transition>() { + @Override + public boolean evaluate(Transition transition) { + if (transitionConditionExpressionEvaluator != null && transition.getConditionExpression() != null) { + log.trace("Evaluating transition expression '{}'.", transition.getConditionExpression()); + return transitionConditionExpressionEvaluator.evaluate(expressionContext, transition.getConditionExpression()); + } + return true; + } + }); + if (t == null) { + throw new ProcessExecutionException("No valid transition starting from process node '" + processNode.getId()+ "'."); + } + log.trace("Found suitable transition: {}", t); + // update pointer + log.trace("Shifting process token from '{}' to '{}'.", pi.getNextId(), t.getTo().getId()); + pi.setNextId(t.getTo().getId()); + + // inspect current task + if (t.getTo() instanceof TaskInfo && (((TaskInfo) t.getTo()).isAsync())) { + // immediately return in case of asynchonous task + log.info("Suspending process instance '{}' for asynchronous task '{}'.", pi.getId(), t.getTo().getId()); + pi.setState(ProcessInstanceState.SUSPENDED); + return; + } + + // continue execution in case of StartEvent or Task + if (processNode instanceof StartEvent || processNode instanceof TaskInfo) { + execute(pi); + } + } + + @Override + public ProcessInstance getProcessInstance(String processInstanceId) { + ProcessInstance processInstance = processInstances.get(processInstanceId); + if (processInstance == null) { + throw new IllegalArgumentException("The process instance '" + processInstanceId + "' does not/no longer exist."); + } + return processInstance; + } + + @Override + public ProcessInstance findProcessInstanceWith(String key, Serializable value) { + Iterator<ProcessInstance> it = processInstances.values().iterator(); + while (it.hasNext()) { + ProcessInstance pi = it.next(); + if (Objects.equals(pi.getExecutionContext().get(key), value)) { + return pi; + } + } + return null; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessExecutionException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessExecutionException.java new file mode 100644 index 000000000..821bbe6dc --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessExecutionException.java @@ -0,0 +1,36 @@ +package at.gv.egovernment.moa.id.process; + +/** + * Indicates a problem when executing a process. + * + * @author tknall + * + */ +public class ProcessExecutionException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Creates a new process execution exception providing a {@code message} describing the reason and the respective + * {@code cause}. + * + * @param message + * The message. + * @param cause + * The cause. + */ + public ProcessExecutionException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new process execution exception providing a {@code message} describing the reason. + * + * @param message + * The message. + */ + public ProcessExecutionException(String message) { + super(message); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstance.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstance.java new file mode 100644 index 000000000..ef69451eb --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstance.java @@ -0,0 +1,166 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.Serializable; +import java.util.Date; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.time.DurationFormatUtils; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.model.ProcessDefinition; +import at.gv.egovernment.moa.id.process.support.SecureRandomHolder; + +/** + * Represents a process being executed. The process instance provides information about the process and its state. + * + * @author tknall + * + */ +public class ProcessInstance implements Serializable { + + private static final long serialVersionUID = 1L; + private static final int RND_ID_LENGTH = 22; + + private ProcessDefinition processDefinition; + private String nextId; + private Date lru; + private ExecutionContext executionContext; + private ProcessInstanceState state = ProcessInstanceState.NOT_STARTED; + + /** + * Creates a new process instance, based on a given process definition.<p/> + * An execution context will be created internally. + * + * @param processDefinition + * The process definition. + */ + ProcessInstance(ProcessDefinition processDefinition) { + this(processDefinition, null); + } + + /** + * Creates a new process instance, based on a given process definition and a + * given execution context. If the given execution context is {@code null} a new execution context will be created.<p/> + * The process instance id of the execution context will automatically be set (and overwritten if already set). + * + * @param processDefinition + * The process definition. + * @param executionContext + * The execution context (may be {@code null}). If {@code null} a new execution context will be created internally. + */ + ProcessInstance(ProcessDefinition processDefinition, ExecutionContext executionContext) { + this.processDefinition = processDefinition; + nextId = processDefinition.getStartEvent().getId(); + String pdIdLocalPart = RandomStringUtils.random(RND_ID_LENGTH, 0, 0, true, true, null, + SecureRandomHolder.getInstance()); + if (executionContext == null) { + executionContext = new ExecutionContextImpl(); + } + executionContext.setProcessInstanceId(this.processDefinition.getId() + "-" + pdIdLocalPart); + this.executionContext = executionContext; + touch(); + } + + /** + * Returns the underlying process definition. + * + * @return The underlying process definition. + */ + ProcessDefinition getProcessDefinition() { + touch(); + return processDefinition; + } + + /** + * Returns the id of the process node to be executed next. + * + * @return The process node pointer indicating the process node to be executed next. + */ + public String getNextId() { + touch(); + return nextId; + } + + /** + * Sets the internal pointer to the process node to be executed next. + * + * @param nextId + * The process node id to be executed next. + */ + void setNextId(String nextId) { + touch(); + this.nextId = nextId; + } + + /** + * Returns the current state of the process instance. + * + * @return The current state. + */ + public ProcessInstanceState getState() { + touch(); + return state; + } + + /** + * Sets the current state of the process instance. + * + * @param state + * The current state. + */ + void setState(ProcessInstanceState state) { + touch(); + this.state = state; + } + + public String getId() { + touch(); + return executionContext.getProcessInstanceId(); + } + + /** + * Updates the last recently used date of the process instance. + */ + private void touch() { + lru = new Date(); + } + + /** + * Returns the date the process instance has been accessed last. + * + * @return The last recently used date. + */ + Date getLru() { + return lru; + } + + /** + * Returns the associated execution context. + * @return The execution context (never {@code null}). + */ + public ExecutionContext getExecutionContext() { + touch(); + return executionContext; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ProcessInstance ["); + builder.append("id=").append(executionContext.getProcessInstanceId()); + builder.append(", idle since=").append( + DurationFormatUtils.formatDurationWords(new Date().getTime() - this.lru.getTime(), true, true)); + if (processDefinition != null) { + builder.append(", processDefinition.id="); + builder.append(processDefinition.getId()); + } + if (nextId != null) { + builder.append(", nextId="); + builder.append(nextId); + } + builder.append(", executionContext=").append(executionContext); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstanceState.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstanceState.java new file mode 100644 index 000000000..2765283a0 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstanceState.java @@ -0,0 +1,30 @@ +package at.gv.egovernment.moa.id.process; + +/** + * Represents a certain process instance state. + * @author tknall + * + */ +public enum ProcessInstanceState { + + /** + * Indicates that the process with this process instance has not yet been started. + */ + NOT_STARTED, + + /** + * Indicates that the process is currently running. + */ + STARTED, + + /** + * Indicates that the process has been suspended until being waken up by someonce calling {@code signal}. + */ + SUSPENDED, + + /** + * Indicates that the process has been completed. + */ + ENDED + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExecutionContext.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExecutionContext.java new file mode 100644 index 000000000..4a9dfc336 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExecutionContext.java @@ -0,0 +1,63 @@ +package at.gv.egovernment.moa.id.process.api; + +import java.io.Serializable; +import java.util.Set; + +/** + * Encapsulates data needed for or provided by task execution. + * + * @author tknall + * + */ +public interface ExecutionContext extends Serializable { + + /** + * Returns the identifier of underlying process instance. + * + * @return The identifier of the process instance. + */ + String getProcessInstanceId(); + + /** + * Sets the identifier of underlying process instance. + * + * @param processInstanceId + * The identifier of the process instance. + */ + void setProcessInstanceId(String processInstanceId); + + /** + * Stores a serializable object using {@code key}. + * + * @param key + * The key under that the {@code object} should be stored. + * @param object The object to be stored. + */ + void put(String key, Serializable object); + + /** + * Returns an serializable object stored within this process context using {@code key}. + * + * @param key + * The key that has been used to store the serializable object (may be {@code null}). + * @return The object or {@code null} in case the key does not relate to a stored object or the stored object itself + * was {@code null}. + */ + Serializable get(String key); + + /** + * Removes the object stored using {@code key}. + * @param key + * The key that has been used to store the serializable object (may be {@code null}). + * @return The object that has been removed or {@code null} there was no object stored using {@code key}. + */ + Serializable remove(String key); + + /** + * Returns an unmodifiable set containing the stored keys. + * + * @return The keyset (never {@code null}). + */ + Set<String> keySet(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluationContext.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluationContext.java new file mode 100644 index 000000000..94854dcad --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluationContext.java @@ -0,0 +1,23 @@ +package at.gv.egovernment.moa.id.process.api; + +import java.io.Serializable; +import java.util.Map; + +import at.gv.egovernment.moa.id.process.model.Transition; + +/** + * Context used for evaluation of condition expressions set for {@linkplain Transition Transitions}. + * + * @author tknall + * + */ +public interface ExpressionEvaluationContext extends Serializable { + + /** + * Returns the context data map used for expression evaluation. + * + * @return An unmodifiable map (never {@code null}). + */ + Map<String, Serializable> getCtx(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluator.java new file mode 100644 index 000000000..fe0743201 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluator.java @@ -0,0 +1,25 @@ +package at.gv.egovernment.moa.id.process.api; + +/** + * Evaluates a given {@code expression} returning a boolean value. + * + * @author tknall + */ +public interface ExpressionEvaluator { + + /** + * Evaluates a given {@code expression} returning a boolean value. + * + * @param expressionContext + * The context which can be used for evaluation of the expression. + * @param expression + * The expression resulting in a boolean (must not be {@code null}). + * @return A boolean value. + * @throws IllegalArgumentException + * In case of an invalid {@code expression}. + * @throws NullPointerException + * In case of a {@code null} expression. + */ + boolean evaluate(ExpressionEvaluationContext expressionContext, String expression); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/Task.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/Task.java new file mode 100644 index 000000000..6401b1d5d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/Task.java @@ -0,0 +1,21 @@ +package at.gv.egovernment.moa.id.process.api; + + +/** + * Represents a single task to be performed upon process execution. + * + * @author tknall + * + */ +public interface Task { + + /** + * Executes this task. + * + * @param executionContext + * Provides execution related information. + * @throws Exception An exception upon task execution. + */ + void execute(ExecutionContext executionContext) throws Exception; + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStore.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStore.java new file mode 100644 index 000000000..c94c95516 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStore.java @@ -0,0 +1,81 @@ +package at.gv.egovernment.moa.id.process.dao; + +import java.io.Serializable; +import java.util.Map; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.Lob; +import javax.persistence.Table; + +import at.gv.egovernment.moa.id.process.ProcessInstanceState; + +@Entity +@Table(name = "processinstance") +public class ProcessInstanceStore { + + @Column(name = "id") + @Id + private int id; + + @Column(name = "processInstanceId", unique = true, nullable = false) + private String processInstanceId; + + @Column(name = "processDefinitionId", nullable = false) + private String processDefinitionId; + + @Column(name = "nextTaskId", nullable = false) + private String nextTaskId; + + @Column(name = "processState", nullable = false) + @Enumerated(value = EnumType.STRING) + private Enum<ProcessInstanceState> processState; + + @Column(name = "executionContextData", nullable = false) + @Lob + private Map<String, Serializable> executionContextData; + + public String getProcessInstanceId() { + return processInstanceId; + } + + public String getProcessDefinitionId() { + return processDefinitionId; + } + + public String getNextTaskId() { + return nextTaskId; + } + + public Enum<ProcessInstanceState> getProcessState() { + return processState; + } + + public Map<String, Serializable> getExecutionContextData() { + return executionContextData; + } + + public void setProcessInstanceId(String processInstanceId) { + this.processInstanceId = processInstanceId; + } + + public void setProcessDefinitionId(String processDefinitionId) { + this.processDefinitionId = processDefinitionId; + } + + public void setNextTaskId(String nextTaskId) { + this.nextTaskId = nextTaskId; + } + + public void setProcessState(Enum<ProcessInstanceState> processState) { + this.processState = processState; + } + + public void setExecutionContextData(Map<String, Serializable> executionContextData) { + this.executionContextData = executionContextData; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStoreDAO.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStoreDAO.java new file mode 100644 index 000000000..57489c33e --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStoreDAO.java @@ -0,0 +1,56 @@ +package at.gv.egovernment.moa.id.process.dao; + +import java.util.List; + +import at.gv.egovernment.moa.id.process.ProcessInstance; + +public interface ProcessInstanceStoreDAO { + + /** + * Stores a {@link ProcessInstance} defined by {@code pIStore} in the + * database. + * + * @param pIStore + * the {@link ProcessInstanceStore} to persist. + */ + void save(ProcessInstanceStore pIStore); + + /** + * Loads a {@link ProcessInstanceStore}, defined by + * {@code processInstanceID} from the database. + * + * @param processInstanceID + * the id of the {@code ProcessInstanceStore} to retrieve. + * @return a ProcessInstanceStore. + */ + ProcessInstanceStore load(String processInstanceId); + + /** + * Deletes the {@link ProcessInstance} corresponding with the + * {@code processInstanceId}. + * + * @param processInstanceID + * the id of the {@code ProcessInstance} to be deleted. + */ + void remove(String processInstanceId); + + /** + * Returns all {@link ProcessInstanceStore} objects stored in the database. + * The returned list may be empty, but never {@code null}. + * + * @return a list of {@link ProcessInstanceStore} (never {@code null}). + */ + List<ProcessInstanceStore> getAllProcessInstanceStores(); + + /** + * Returns the specific {@link ProcessInstanceStore} object corresponding to + * the given {@code processInstanceId}, or {@code null} if the object could + * not be found. + * + * @param processInstanceId + * the processInstanceId to search. + * @return the ProcessInstanceStore for the given id, or {@code null}. + */ + ProcessInstanceStore getProcessInstance(String processInstanceId); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStoreDAOImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStoreDAOImpl.java new file mode 100644 index 000000000..cde34acd1 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/dao/ProcessInstanceStoreDAOImpl.java @@ -0,0 +1,51 @@ +package at.gv.egovernment.moa.id.process.dao; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Database backed implementation of the {@link ProcessInstanceStoreDAO} + * interface. + */ +public class ProcessInstanceStoreDAOImpl implements ProcessInstanceStoreDAO { + + private Logger log = LoggerFactory.getLogger(getClass()); + + private static ProcessInstanceStoreDAO instance = new ProcessInstanceStoreDAOImpl(); + + public static ProcessInstanceStoreDAO getInstance() { + return instance; + } + + @Override + public void save(ProcessInstanceStore pIStore) { + // TODO Auto-generated method stub + } + + @Override + public ProcessInstanceStore load(String processInstanceID) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void remove(String processInstanceId) { + // TODO Auto-generated method stub + + } + + @Override + public List<ProcessInstanceStore> getAllProcessInstanceStores() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ProcessInstanceStore getProcessInstance(String processInstanceId) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/EndEvent.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/EndEvent.java new file mode 100644 index 000000000..49fb082ea --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/EndEvent.java @@ -0,0 +1,42 @@ +package at.gv.egovernment.moa.id.process.model; + +import java.io.Serializable; + +import org.apache.commons.collections4.CollectionUtils; + +/** + * Represents an end event. Process execution terminates when an end event is reached. + * + * @author tknall + */ +public class EndEvent extends ProcessNode implements Serializable { + + private static final long serialVersionUID = 1L; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("EndEvent ["); + if (getId() != null) { + builder.append("id="); + builder.append(getId()); + } + if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("incomingTransitions="); + builder.append(getIncomingTransitions()); + } + if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("outgoingTransitions="); + builder.append(getOutgoingTransitions()); + } + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessDefinition.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessDefinition.java new file mode 100644 index 000000000..518409ecf --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessDefinition.java @@ -0,0 +1,158 @@ +package at.gv.egovernment.moa.id.process.model; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +import at.gv.egovernment.moa.id.process.ProcessDefinitionParser; + +/** + * Represents a single process definition containing + * <ul> + * <li>a {@link StartEvent},</li> + * <li>one or more {@linkplain TaskInfo Tasks},</li> + * <li>one or more {@linkplain EndEvent EndEvents} and</li> + * <li>some {@linkplain Transition Transitions} linking StartEvents, Tasks and EndEvents. + * </ul> + * + * @author tknall + * + */ +public class ProcessDefinition { + + private String id; + private StartEvent startEvent; + private Map<String, TaskInfo> taskInfos = new LinkedHashMap<>(); + private Map<String, EndEvent> endEvents = new LinkedHashMap<>(); + + /** + * Returns the unique identifier of the process definition. + * + * @return The unique identifier (never {@code null} if process definition comes from + * {@link ProcessDefinitionParser}). + */ + public String getId() { + return id; + } + + /** + * Sets the unique identifier of the process definition. + * + * @param id + * The unique identifier. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Returns the start event of the process definition. + * + * @return The start event (never {@code null} if process definition comes from {@link ProcessDefinitionParser}). + */ + public StartEvent getStartEvent() { + return startEvent; + } + + /** + * Sets the start event of the process definition. + * + * @param startEvent + * The start event. + */ + public void setStartEvent(StartEvent startEvent) { + this.startEvent = startEvent; + } + + /** + * Returns a map containing the tasks of the process definition. + * + * @return The tasks (map is never {@code null} if process definition comes from {@link ProcessDefinitionParser}). + */ + public Map<String, TaskInfo> getTaskInfos() { + return taskInfos; + } + + /** + * Sets the map containing the tasks. + * + * @param taskInfos + * The map containing the tasks. + */ + public void setTaskInfos(Map<String, TaskInfo> taskInfos) { + this.taskInfos = taskInfos; + } + + /** + * Returns a map containing the end events of the process description. + * + * @return The map containing the end events (map is never {@code null} if process definition comes from + * {@link ProcessDefinitionParser}). + */ + public Map<String, EndEvent> getEndEvents() { + return endEvents; + } + + /** + * Sets a map containing the end events of the process description. + * + * @param endEvents + * The map containing the end events. + */ + public void setEndEvents(Map<String, EndEvent> endEvents) { + this.endEvents = endEvents; + } + + /** + * Returns the process node associated with the given {@code id}. + * + * @param id + * The identifier of the process node. + * @return The process node (may be {code null} when no process node with the given {@code id} exists). + */ + public ProcessNode getProcessNode(String id) { + Objects.requireNonNull(id, "Identifier must not be null."); + if (startEvent != null && id.equals(startEvent.getId())) { + return startEvent; + } + TaskInfo task = taskInfos.get(id); + if (task != null) { + return task; + } + return endEvents.get(id); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (id != null) { + builder.append("id="); + builder.append(id); + } + if (startEvent != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("startEvent="); + builder.append(startEvent); + } + if (taskInfos != null && !taskInfos.isEmpty()) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("tasksInfos="); + builder.append(taskInfos.values()); + } + if (endEvents != null && !endEvents.isEmpty()) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("endEvents="); + builder.append(endEvents.values()); + } + builder.insert(0, "ProcessDefinition ["); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessNode.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessNode.java new file mode 100644 index 000000000..42f2e3cc2 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessNode.java @@ -0,0 +1,69 @@ +package at.gv.egovernment.moa.id.process.model; + +import java.util.ArrayList; +import java.util.List; + +import at.gv.egovernment.moa.id.process.ProcessDefinitionParser; + +/** + * Represents a {@link StartEvent}, an {@link EndEvent} or a {@linkplain TaskInfo Task}. + * @author tknall + * + */ +public abstract class ProcessNode { + + private String id; + private List<Transition> outgoingTransitions = new ArrayList<>(); + private List<Transition> incomingTransitions = new ArrayList<>(); + + /** + * Returns the unique identifier of the process node. + * + * @return The unique identifier (never {@code null} if process node comes from a process definition from + * {@link ProcessDefinitionParser}). + */ + public String getId() { + return id; + } + + /** + * Sets the unique identifier of the process node. + * @param id The unique identifier. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Returns a list of transitions pointing from this process node to another one. + * @return A list of transitions (never {@code null} if process node comes from a process definition from {@link ProcessDefinitionParser}). + */ + public List<Transition> getOutgoingTransitions() { + return outgoingTransitions; + } + + /** + * Sets the list of transitions pointing from this process node to another one. + * @param outgoingTransitions The list of transitions originating from this process node. + */ + public void setOutgoingTransitions(List<Transition> outgoingTransitions) { + this.outgoingTransitions = outgoingTransitions; + } + + /** + * Returns a list of transitions pointing from another process node to this one. + * @return A list of transitions (never {@code null} if process node comes from a process definition from {@link ProcessDefinitionParser}). + */ + public List<Transition> getIncomingTransitions() { + return incomingTransitions; + } + + /** + * Sets the list of transitions pointing from another process node to this one. + * @param incomingTransitions A list of transitions pointing to this process node. + */ + public void setIncomingTransitions(List<Transition> incomingTransitions) { + this.incomingTransitions = incomingTransitions; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/StartEvent.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/StartEvent.java new file mode 100644 index 000000000..60175e09c --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/StartEvent.java @@ -0,0 +1,45 @@ +package at.gv.egovernment.moa.id.process.model; + +import java.io.Serializable; + +import org.apache.commons.collections4.CollectionUtils; + +/** + * Represents a start event. Each process description contains a single start event. Process execution starts with a + * start event. + * + * @author tknall + * + */ +public class StartEvent extends ProcessNode implements Serializable { + + private static final long serialVersionUID = 1L; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("StartEvent ["); + if (getId() != null) { + builder.append("id="); + builder.append(getId()); + } + if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("incomingTransitions="); + builder.append(getIncomingTransitions()); + } + if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("outgoingTransitions="); + + builder.append(getOutgoingTransitions()); + } + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/TaskInfo.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/TaskInfo.java new file mode 100644 index 000000000..78a9d6a0a --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/TaskInfo.java @@ -0,0 +1,94 @@ +package at.gv.egovernment.moa.id.process.model; + +import java.io.Serializable; + +import org.apache.commons.collections4.CollectionUtils; + +import at.gv.egovernment.moa.id.process.api.Task; + +/** + * Represents information about a single task to be performed upon process execution. + * @author tknall + * + */ +public class TaskInfo extends ProcessNode implements Serializable { + + private static final long serialVersionUID = 1L; + private static final boolean DEFAULT_ASYNC = false; + + private String taskImplementingClass; + private boolean async = DEFAULT_ASYNC; + + /** + * Determines if the task is marked asynchronous ({@code true}) or synchronous ({@code false}). + * @return A flag indicating if the task should be executed asynchronously or synchronously. (Default: {@code false}) + */ + public boolean isAsync() { + return async; + } + + /** + * Marks a task to executed asynchronously ({@code true}) or synchronously ({@code false}). + * @param async The flag. + */ + public void setAsync(boolean async) { + this.async = async; + } + + /** + * Returns the class that implements the actual task (must implement {@link Task}). + * @return The task implementing class. + */ + public String getTaskImplementingClass() { + return taskImplementingClass; + } + + /** + * Sets the class that implements the actual task (must implement {@link Task}). + * @param taskImplementingClass The task implementing class. + */ + public void setTaskImplementingClass(String taskImplementingClass) { + this.taskImplementingClass = taskImplementingClass; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (getId() != null) { + builder.append("id="); + builder.append(getId()); + } + if (async != DEFAULT_ASYNC) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("async="); + builder.append(async); + } + if (taskImplementingClass != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("taskImplementingClass="); + builder.append(taskImplementingClass); + } + if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("incomingTransitions="); + builder.append(getIncomingTransitions()); + } + if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("outgoingTransitions="); + builder.append(getOutgoingTransitions()); + } + builder.insert(0, "TaskInfo ["); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/Transition.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/Transition.java new file mode 100644 index 000000000..bc3005534 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/Transition.java @@ -0,0 +1,136 @@ +package at.gv.egovernment.moa.id.process.model; + +import java.io.Serializable; + +import at.gv.egovernment.moa.id.process.ProcessDefinitionParser; + +/** + * Represents a single transition from a {@link StartEvent} or {@linkplain TaskInfo Task} to another + * {@linkplain TaskInfo Task} or {@link EndEvent}. + * + * @author tknall + * + */ +public class Transition implements Serializable { + + private static final long serialVersionUID = 1L; + + private String id; + private String conditionExpression; + private ProcessNode from; + private ProcessNode to; + + /** + * Returns the process node (effectively a {@link StartEvent} or {@linkplain TaskInfo Task}) the transition is + * pointing from. + * + * @return The transition's source process node (never {@code null} if transition comes from a process definition + * from {@link ProcessDefinitionParser}). + */ + public ProcessNode getFrom() { + return from; + } + + /** + * Sets the process node the transition is pointing from. + * + * @param from + * The transition's source process node. + */ + public void setFrom(ProcessNode from) { + this.from = from; + } + + /** + * Returns the process node (effectively a {@linkplain TaskInfo Task} or {@link EndEvent}) the transition is + * pointing to. + * + * @return The transition's destination process node (never {@code null} if transition comes from a process + * definition from {@link ProcessDefinitionParser}). + */ + public ProcessNode getTo() { + return to; + } + + /** + * Sets the process node the transition is pointing to. + * + * @param to + * The transition's destination process node. + */ + public void setTo(ProcessNode to) { + this.to = to; + } + + /** + * Returns the unique identifier of the transition. + * + * @return The unique identifier (may be {@code null}). + */ + public String getId() { + return id; + } + + /** + * Sets the unique identifier of the transition. + * + * @param id + * The unique identifier. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Returns the condition expression for this transition. + * + * @return The condition expression (may be {@code null}). + */ + public String getConditionExpression() { + return conditionExpression; + } + + /** + * Sets the condition expression for this transition. + * + * @param conditionExpression + * The condition expression. + */ + public void setConditionExpression(String conditionExpression) { + this.conditionExpression = conditionExpression; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (id != null) { + builder.append("id="); + builder.append(id); + } + if (from != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("from.id="); + builder.append(from.getId()); + } + if (to != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("to.id="); + builder.append(to.getId()); + } + if (conditionExpression != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("conditionExpression="); + builder.append(conditionExpression); + } + builder.insert(0, "Transition ["); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/spring/SpringExpressionEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/spring/SpringExpressionEvaluator.java new file mode 100644 index 000000000..5b30c7172 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/spring/SpringExpressionEvaluator.java @@ -0,0 +1,61 @@ +package at.gv.egovernment.moa.id.process.spring; + +import java.util.Objects; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.BooleanUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluationContext; +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluator; +import at.gv.egovernment.moa.id.process.model.Transition; + +/** + * Expression evaluator for processing {@link Transition} conditions allowing to reference Spring beans from the + * application context. + * + * @author tknall + * + */ +public class SpringExpressionEvaluator implements ExpressionEvaluator { + + private Logger log = LoggerFactory.getLogger(getClass()); + private ExpressionParser parser = new SpelExpressionParser(); + private StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + + @Autowired(required = false) + private ApplicationContext ctx; + + @PostConstruct + private void init() { + if (ctx != null) { + evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx)); + } + } + + @Override + public boolean evaluate(ExpressionEvaluationContext expressionContext, String expression) { + Objects.requireNonNull(expression, "Expression must not be null."); + log.trace("Evaluating '{}'.", expression); + + Expression expr = parser.parseExpression(expression); + Boolean result = expr.getValue(evaluationContext, expressionContext, Boolean.class); + if (result == null) { + log.warn("Evaluation of '{}' results in null-value.", expression); + } else { + log.debug("Expression '{}' -> {}", expression, result); + } + + return BooleanUtils.isTrue(result); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractAuthSourceServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractAuthSourceServlet.java new file mode 100644 index 000000000..738b58834 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractAuthSourceServlet.java @@ -0,0 +1,116 @@ +package at.gv.egovernment.moa.id.process.springweb; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.NoUniqueBeanDefinitionException; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +import at.gv.egovernment.moa.id.process.ProcessEngine; +import at.gv.egovernment.moa.id.process.ProcessInstance; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; + +/** + * Abstract HttpServlet that provides means for retrieving the process engine (Spring Web required) as well as + * retrieving the underlying process instance and execution context evaluating a certain request parameter. + * + * @author tknall + * + */ +public abstract class AbstractAuthSourceServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private ProcessEngine processEngine; + + /** + * Returns the name of the request parameter representing the respective instance id. + * <p/>Default is {@code processInstanceId}. + * @return The request parameter name. + */ + public String getProcessInstanceIdParameterName() { + return "processInstanceId"; + } + + /** + * Returns the underlying process engine instance. + * + * @return The process engine (never {@code null}). + * @throws NoSuchBeanDefinitionException + * if no {@link ProcessEngine} bean was found. + * @throws NoUniqueBeanDefinitionException + * if more than one {@link ProcessEngine} bean was found. + * @throws BeansException + * if a problem getting the {@link ProcessEngine} bean occurred. + * @throws IllegalStateException + * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a + * Spring web environment. + */ + public synchronized ProcessEngine getProcessEngine() { + if (processEngine == null) { + WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); + if (ctx == null) { + throw new IllegalStateException( + "Unable to find Spring WebApplicationContext. Servlet needs to be executed within a Spring web environment."); + } + processEngine = ctx.getBean(ProcessEngine.class); + } + return processEngine; + } + + /** + * Retrieves the process instance referenced by the request parameter {@link #getProcessInstanceIdParameterName()}. + * + * @param request + * The HttpServletRequest. + * @return The process instance (never {@code null}). + * @throws NoSuchBeanDefinitionException + * if no {@link ProcessEngine} bean was found. + * @throws NoUniqueBeanDefinitionException + * if more than one {@link ProcessEngine} bean was found. + * @throws BeansException + * if a problem getting the {@link ProcessEngine} bean occurred. + * @throws IllegalStateException + * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a + * Spring web environment. + * @throws IllegalArgumentException + * in case the process instance id referenced by the request parameter + * {@link #getProcessInstanceIdParameterName()} does not exist. + */ + public ProcessInstance getProcessInstance(HttpServletRequest request) { + String processInstanceId = StringUtils.trimToNull(request.getParameter(getProcessInstanceIdParameterName())); + if (processInstanceId == null) { + throw new IllegalArgumentException("Missing request parameter '" + getProcessInstanceIdParameterName() + "'."); + } + return getProcessEngine().getProcessInstance(processInstanceId); + } + + /** + * Retrieves the execution context for the respective process instance referenced by the request parameter + * {@link #getProcessInstanceIdParameterName()}. + * + * @param request + * The HttpServletRequest. + * @return The execution context (never {@code null}). + * @throws NoSuchBeanDefinitionException + * if no {@link ProcessEngine} bean was found. + * @throws NoUniqueBeanDefinitionException + * if more than one {@link ProcessEngine} bean was found. + * @throws BeansException + * if a problem getting the {@link ProcessEngine} bean occurred. + * @throws IllegalStateException + * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a + * Spring web environment. + * @throws IllegalArgumentException + * in case the process instance id referenced by the request parameter + * {@link #getProcessInstanceIdParameterName()} does not exist. + */ + public ExecutionContext getExecutionContext(HttpServletRequest request) { + return getProcessInstance(request).getExecutionContext(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractSpringWebSupportedTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractSpringWebSupportedTask.java new file mode 100644 index 000000000..c9262cea9 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractSpringWebSupportedTask.java @@ -0,0 +1,73 @@ +package at.gv.egovernment.moa.id.process.springweb; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.filter.RequestContextFilter; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.api.Task; + +/** + * Abstract task implementation providing {@link HttpServletRequest} and {@link HttpServletResponse}. + * <p/> + * Note that this abstract task requires the Spring (web) framework including a {@link RequestContextFilter} to be set + * within {@code web.xml}. + * + * <pre> + * ... + * <filter> + * <filter-name>requestContextFilter</filter-name> + * <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> + * </filter> + * <filter-mapping> + * <filter-name>requestContextFilter</filter-name> + * <url-pattern>/*</url-pattern> + * </filter-mapping> + * ... + * </pre> + * + * @author tknall + * + */ +public abstract class AbstractSpringWebSupportedTask implements Task { + + /** + * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext} as well as the + * respective {@link HttpServletRequest} and {@link HttpServletResponse}. + * + * @param executionContext + * The execution context (never {@code null}). + * @param request + * The HttpServletRequest (never {@code null}). + * @param response + * The HttpServletResponse (never {@code null}). + * @throws IllegalStateException + * Thrown in case the task is nur being run within the required environment. Refer to javadoc for + * further information. + * @throws Exception + * Thrown in case of error executing the task. + */ + public abstract void execute(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) throws Exception; + + @Override + public void execute(ExecutionContext executionContext) throws Exception { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null && requestAttributes instanceof ServletRequestAttributes) { + HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); + HttpServletResponse response = ((ServletRequestAttributes) requestAttributes).getResponse(); + if (request == null || response == null) { + throw new IllegalStateException( + "Spring's RequestContextHolder did not provide HttpServletResponse. Did you forget to set the required org.springframework.web.filter.RequestContextFilter in your web.xml."); + } + execute(executionContext, request, response); + } else { + throw new IllegalStateException("Task needs to be executed within a Spring web environment."); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java new file mode 100644 index 000000000..9dd7bc61e --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/SpringWebExpressionEvaluator.java @@ -0,0 +1,137 @@ +package at.gv.egovernment.moa.id.process.springweb; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluationContext; +import at.gv.egovernment.moa.id.process.api.ExpressionEvaluator; +import at.gv.egovernment.moa.id.process.model.Transition; + +/** + * Expression evaluator for processing {@link Transition} conditions allowing to + * <ul> + * <li>reference Spring beans from the application context using {@code @myBeanName...},</li> + * <li>{@link ExecutionContext} properties using {@code ctx['property']},</li> + * <li>Multi valued {@link HttpServletRequest} parameters using {@code requestParameters['foo']} (keep in mind that this + * expression returns an array of String values) and</li> + * <li>Single valued {@link HttpServletRequest} parameters using {@code requestParameter['foo']}</li> + * </ul> + * + * @author tknall + * + */ +public class SpringWebExpressionEvaluator implements ExpressionEvaluator { + + private Logger log = LoggerFactory.getLogger(getClass()); + private ExpressionParser parser = new SpelExpressionParser(); + private StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + + @Autowired(required = false) + private ApplicationContext ctx; + + @Autowired(required = false) + private HttpServletRequest request; + + @PostConstruct + private void init() { + if (ctx != null) { + evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx)); + } + } + + /** + * Evaluation context that provides access to {@link HttpServletRequest} parameters using + * {@code requestParameter['foo']} for single value parameters or {@code requestParameters['foo']} for multi value + * parameters. Basic calls to {@code ctx} will be delegated. + * + * @author tknall + * + */ + private class SpringWebExpressionEvaluationContext implements ExpressionEvaluationContext { + + private static final long serialVersionUID = 1L; + + /** + * Creates a new expression evaluation context, providing access to HttpServletRequest parameter(s). + * + * @param delegate + * The original {@link ExpressionEvaluationContext} to be delegated to for {@code ctx['foo']} + * expressions. + */ + public SpringWebExpressionEvaluationContext(ExpressionEvaluationContext delegate) { + this.delegate = delegate; + } + + private ExpressionEvaluationContext delegate; + + @Override + public Map<String, Serializable> getCtx() { + return delegate.getCtx(); + } + + @SuppressWarnings("unused") + public Map<String, String> getRequestParameter() { + if (request != null) { + Map<String, String> singleValueMap = new HashMap<String, String>(); + Iterator<Entry<String, String[]>> it = request.getParameterMap().entrySet().iterator(); + while (it.hasNext()) { + Entry<String, String[]> entry = it.next(); + if (ArrayUtils.isNotEmpty(entry.getValue())) { + singleValueMap.put(entry.getKey(), entry.getValue()[0]); + } + } + return singleValueMap; + } else { + return Collections.<String, String> emptyMap(); + } + } + + @SuppressWarnings("unused") + public Map<String, String[]> getRequestParameters() { + if (request != null) { + return request.getParameterMap(); + } else { + return Collections.<String, String[]> emptyMap(); + } + } + + } + + @Override + public boolean evaluate(ExpressionEvaluationContext expressionContext, String expression) { + Objects.requireNonNull(expression, "Expression must not be null."); + log.trace("Evaluating '{}'.", expression); + + Expression expr = parser.parseExpression(expression); + Boolean result = expr.getValue(evaluationContext, new SpringWebExpressionEvaluationContext(expressionContext), + Boolean.class); + if (result == null) { + log.warn("Evaluation of '{}' results in null-value.", expression); + } else { + log.debug("Expression '{}' -> {}", expression, result); + } + + return BooleanUtils.isTrue(result); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/support/SecureRandomHolder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/support/SecureRandomHolder.java new file mode 100644 index 000000000..72677739a --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/support/SecureRandomHolder.java @@ -0,0 +1,35 @@ +package at.gv.egovernment.moa.id.process.support; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +/** + * Holder for a secure random instance following the initialization on demand holder design pattern. The secure random + * instance is a singleton that is initialized on first usage. + * + * @author tknall + * + */ +public class SecureRandomHolder { + + private SecureRandomHolder() { + } + + private static final SecureRandom SRND_INSTANCE; + static { + try { + SRND_INSTANCE = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Unable to instantiate SHA1PRNG.", e); + } + } + + /** + * Returns a secure random generator instance. + * @return The secure random instance. + */ + public static SecureRandom getInstance() { + return SecureRandomHolder.SRND_INSTANCE; + } + +}
\ No newline at end of file |