Java tutorial
/** * This file belongs to the BPELUnit utility and Eclipse plugin set. See enclosed * license file for more information. * */ package net.bpelunit.framework.control.deploy.activebpel; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.soap.SOAPException; import net.bpelunit.framework.control.deploy.IBPELDeployer; import net.bpelunit.framework.control.deploy.IBPELDeployer.IBPELDeployerCapabilities; import net.bpelunit.framework.control.deploy.IDeployment; import net.bpelunit.framework.control.util.NoPersistenceConnectionManager; import net.bpelunit.framework.exception.DeploymentException; import net.bpelunit.framework.model.ProcessUnderTest; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.log4j.Logger; /** * ActiveBPEL Deployer - deploys a process to an ActiveBPEL server. * * By default, the application server running ActiveBPEL is considered to be * listening at http://localhost:8080, and deployment archives are stored at * $CATALINA_HOME/bpr, where $CATALINA_HOME is an environment variable that * needs to be set to the home directory of the application server. * * If ActiveBPEL is password protected, users can specify a username and a * password. By default, these are not set. * * @author Philip Mayer, Antonio Garcia-Dominguez */ @IBPELDeployerCapabilities(canDeploy = true, canMeasureTestCoverage = true) public class ActiveBPELDeployer implements IBPELDeployer { private static final int HTTP_OK = 200; /* * Encapsulates the results from an HTTP request: status code and response * body */ private static class RequestResult { private int statusCode; private String responseBody; public void setStatusCode(int statusCode) { this.statusCode = statusCode; } public int getStatusCode() { return statusCode; } public void setResponseBody(String responseBody) { this.responseBody = responseBody; } public String getResponseBody() { return responseBody; } } // Strings which enclose the number of deployment errors in the summary private static final String ERRCOUNT_START = "<deploymentSummary numErrors=""; private static final String ERRCOUNT_END = """; /* Default URLs for the deployment and administration web services */ static final String DEFAULT_DEPLOYMENT_URL = "http://localhost:8080/active-bpel/services/DeployBPRService"; static final String DEFAULT_ADMIN_URL = "http://localhost:8080/active-bpel/services/ActiveBpelAdmin"; /* * Name of the environment variable which will be used to build the * deployment directory if no configuration has been specified. */ static final String DEFAULT_APPSERVER_DIR_ENVVAR = "CATALINA_HOME"; private Logger fLogger = Logger.getLogger(getClass()); private String fResultingFile; private File fBPRFile; private String fDeploymentDirectory; private String fDeploymentAdminServiceURL = DEFAULT_DEPLOYMENT_URL; private String fAdminServiceURL = DEFAULT_ADMIN_URL; private String fUsername = "", fPassword = ""; private ProcessUnderTest put; /* for unit testing */ private static int terminatedProcessCount = 0; @IBPELDeployerOption(testSuiteSpecific = false) public void setBPRFile(String bprFile) { this.fBPRFile = new File(bprFile); } @IBPELDeployerOption public void setDeploymentDirectory(String deploymentDirectory) { if (deploymentDirectory != null) { this.fDeploymentDirectory = deploymentDirectory; } } public String getDeploymentAdminServiceURL() { return fDeploymentAdminServiceURL; } @IBPELDeployerOption(defaultValue = DEFAULT_DEPLOYMENT_URL) public void setDeploymentAdminServiceURL(String deploymentAdminServiceURL) { if (deploymentAdminServiceURL != null) { this.fDeploymentAdminServiceURL = deploymentAdminServiceURL; } } public String getAdministrationServiceURL() { return fAdminServiceURL; } @IBPELDeployerOption(defaultValue = DEFAULT_ADMIN_URL) public void setAdministrationServiceURL(String adminServiceURL) { if (adminServiceURL != null) { this.fAdminServiceURL = adminServiceURL; } } public String getUsername() { return fUsername; } @IBPELDeployerOption(defaultValue = "") public void setUsername(String fUsername) { this.fUsername = fUsername; } public String getPassword() { return fPassword; } @IBPELDeployerOption(defaultValue = "") public void setPassword(String fPassword) { this.fPassword = fPassword; } public void deploy(String pathToTest, ProcessUnderTest put) throws DeploymentException { this.put = put; fLogger.info("ActiveBPEL deployer got request to deploy " + put); if (fDeploymentDirectory == null && System.getenv(DEFAULT_APPSERVER_DIR_ENVVAR) != null) { fDeploymentDirectory = System.getenv(DEFAULT_APPSERVER_DIR_ENVVAR) + File.separator + "bpr"; } check(fBPRFile, "BPR File"); check(fDeploymentDirectory, "deployment directory path"); check(fDeploymentAdminServiceURL, "deployment admin server URL"); check(fAdminServiceURL, "engine admin server URL"); // changed the way the archive location is obtained. boolean fileReplaced = false; String archivePath = getArchiveLocation(pathToTest); File uploadingFile = new File(archivePath); if (!uploadingFile.exists()) { throw new DeploymentException("ActiveBPEL deployer could not find BPR file " + fBPRFile); } File resultingFile = new File(fDeploymentDirectory, fBPRFile.getName()); // Upload it. RequestEntity re; try { re = new BPRDeployRequestEntity(uploadingFile); } catch (IOException e) { throw new DeploymentException( "An input/output error occured in ActivBPEL deployer when deploying: " + e.getMessage(), e); } catch (SOAPException e) { throw new DeploymentException( "An error occurred while creating SOAP message for ActiveBPEL deployment: " + e.getMessage(), e); } fLogger.info("ActiveBPEL deployer about to send SOAP request to deploy " + put); try { RequestResult result = sendRequestToActiveBPEL(fDeploymentAdminServiceURL, re); if (result.getStatusCode() < 200 || result.getStatusCode() > 299 || errorsInSummary(result.getResponseBody())) { throw new DeploymentException( "ActiveBPEL Server reported a Deployment Error: " + result.getResponseBody()); } // done. fResultingFile = resultingFile.toString(); } catch (HttpException e) { throw new DeploymentException("Problem contacting the ActiveBPEL Server: " + e.getMessage(), e); } catch (IOException e) { throw new DeploymentException("Problem contacting the ActiveBPEL Server: " + e.getMessage(), e); } finally { if (fileReplaced && uploadingFile.exists()) { uploadingFile.delete(); } } } public void undeploy(String path, ProcessUnderTest deployable) throws DeploymentException { // undeploy may be called even if deploy was not successful if (fResultingFile == null) { return; } File bprFile = new File(fResultingFile); if (fResultingFile == null) { throw new DeploymentException( "Cannot undeploy BPR for Deployable " + deployable + ": Metadata about file name not found."); } if (!bprFile.exists()) { throw new DeploymentException( "Cannot undeploy BPR for Deployable " + deployable + ": File " + bprFile + " not found."); } if (!bprFile.delete()) { throw new DeploymentException("Cannot undeploy BPR for Deployable " + deployable + ": File " + bprFile + " could not be deleted."); } try { terminateAllRunningProcesses(deployable.getName()); } catch (Exception e) { throw new DeploymentException(e.getLocalizedMessage(), e); } } private String getArchiveLocation(String pathToTest) { try { if (fBPRFile.isAbsolute()) { // absolute paths are left as is return fBPRFile.getCanonicalPath(); } else { // relative paths are resolved from the directory of the .bpts return new File(pathToTest, fBPRFile.getName()).getCanonicalPath(); } } catch (IOException e) { // if the path cannot be cleaned up, just turn it into an absolute path return fBPRFile.getAbsolutePath(); } } private void check(Object toCheck, String description) throws DeploymentException { if (toCheck == null) { throw new DeploymentException( "ActiveBPEL deployment configuration is missing the " + description + "."); } } /** * @param re SOAP request entity to be sent to ActiveBPEL. * @return Response from the ActiveBPEL administration service. * @throws IOException */ private RequestResult sendRequestToActiveBPEL(final String url, RequestEntity re) throws IOException { PostMethod method = null; try { HttpClient client = new HttpClient(new NoPersistenceConnectionManager()); if (fUsername != null && !"".equals(fUsername) && fPassword != null && !"".equals(fPassword)) { client.getState().setCredentials(new AuthScope(null, -1), new UsernamePasswordCredentials(fUsername, fPassword)); } method = new PostMethod(url); method.setRequestEntity(re); // Provide custom retry handler is necessary method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(1, false)); method.addRequestHeader("SOAPAction", ""); client.executeMethod(method); // We need to read the response body right now: if it is called // after the connection is released, it will only return null RequestResult result = new RequestResult(); result.setStatusCode(method.getStatusCode()); result.setResponseBody(method.getResponseBodyAsString()); return result; } finally { if (method != null) { method.releaseConnection(); } } } private void terminateAllRunningProcesses(String processName) throws DeploymentException { for (int pid : listRunningProcesses(processName)) { terminateProcess(pid); } } private List<Integer> listRunningProcesses(String processName) throws DeploymentException { try { ArrayList<Integer> vProcesses = new ArrayList<Integer>(); RequestResult listResponse = sendRequestToActiveBPEL(fAdminServiceURL, new ProcessListRequestEntity(processName)); if (listResponse.getStatusCode() != HTTP_OK) { throw new DeploymentException(String.format( "Could not obtain the running process list: " + "got status code %d\nResponse:\n%s", listResponse.getStatusCode(), listResponse.getResponseBody())); } // No need to perform XML parsing: we're only interested // in some simple elements Pattern patPID = Pattern.compile("<[^>]*processId>\\s*([0-9]+)\\s*</[^>]+>"); Matcher matcher = patPID.matcher(listResponse.getResponseBody()); while (matcher.find()) { vProcesses.add(Integer.parseInt(matcher.group(1))); } return vProcesses; } catch (Exception e) { throw new DeploymentException("Could not obtain the running process list: " + e.toString(), e); } } private void terminateProcess(int pid) throws DeploymentException { try { ++terminatedProcessCount; RequestResult response = sendRequestToActiveBPEL(fAdminServiceURL, new TerminateProcessRequestEntity(pid)); if (response.getStatusCode() != 200) { throw new Exception( String.format("Could not kill process #%d: " + "non-OK status code %d\nResponse:\n%s", pid, response.getStatusCode(), response.getResponseBody())); } } catch (Exception e) { throw new DeploymentException(String.format("Could not kill process #%d: %s", pid, e.toString()), e); } } private boolean errorsInSummary(String responseBody) { int startErrorCount = responseBody.indexOf(ERRCOUNT_START); if (startErrorCount == -1) { return false; } startErrorCount += ERRCOUNT_START.length(); final int endErrorCount = responseBody.indexOf(ERRCOUNT_END, startErrorCount); if (endErrorCount == -1) { return false; } final String sErrorCount = responseBody.substring(startErrorCount, endErrorCount); final int errorCount = Integer.parseInt(sErrorCount); return errorCount > 0; } public void cleanUpAfterTestCase() throws DeploymentException { terminateAllRunningProcesses(put.getName()); } static int getTerminatedProcessCount() { return terminatedProcessCount; } @Override public IDeployment getDeployment(ProcessUnderTest processUnderTest) throws DeploymentException { // TODO Auto-generated method stub return null; } }