From 6f1d01394ddf78b2c202fb2f46ba41a8d9334a3a Mon Sep 17 00:00:00 2001 From: Martin Bergljung Date: Thu, 16 Feb 2017 10:45:51 +0000 Subject: [PATCH] Initial check-in of Bindu's AlfrescoTestRunner frameowork plus sample tests, #401 --- .../resources/archetype-resources/pom.xml | 2 +- .../__rootArtifactId__-platform-jar/pom.xml | 7 - .../src/main/java/platformsample/Demo.java | 17 + .../java/platformsample/DemoComponent.java | 35 +- .../platformsample/HelloWorldWebScript.java | 33 +- .../context/service-context.xml | 6 +- .../platformsample/CustomContentModelIT.java | 191 +++ .../java/platformsample/DemoComponentIT.java | 73 + .../HelloWorldWebScriptControllerTest.java | 56 + .../platformsample/HelloWorldWebScriptIT.java | 75 + .../resources/archetype-resources/pom.xml | 46 + .../java/platformsample/DemoComponent.java | 2 +- .../context/service-context.xml | 6 +- modules/alfresco-rad/pom.xml | 134 +- .../maven/rad/RemoteRunnerWrapper.java | 16 - .../org/alfresco/rad/SpringContextHolder.java | 69 + .../alfresco/rad/test/AbstractAlfrescoIT.java | 89 ++ .../alfresco/rad/test/AlfrescoTestRunner.java | 249 +++ .../java/org/alfresco/rad/test/Remote.java | 43 + .../alfresco/rad/test/RunTestWebScript.java | 154 ++ .../alfresco/extension/rad-context.xml | 46 +- .../alfresco/rad/test/runtest.get.desc.xml | 37 + .../alfresco/rad/test/runtest.get.html.ftl | 34 + .../org/alfresco/rad/test/runtest.get.xml.ftl | 27 + .../plugin/AbstractRefreshWebappMojo.java | 2 +- .../maven/plugin/AbstractRunMojo.java | 1391 +++++++++++++++++ .../alfresco/maven/plugin/InstallMojo.java | 17 + .../maven/plugin/IntegrationTestMojo.java | 274 ++++ .../alfresco/maven/plugin/RefreshMojo.java | 2 +- .../maven/plugin/RefreshRepoWebappMojo.java | 2 +- .../maven/plugin/RefreshShareWebappMojo.java | 2 +- .../org/alfresco/maven/plugin/RunMojo.java | 1365 +--------------- .../alfresco/maven/plugin/ValidateMojo.java | 19 +- .../alfresco/maven/plugin/VersionMojo.java | 17 + pom.xml | 2 +- 35 files changed, 2980 insertions(+), 1560 deletions(-) create mode 100644 archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/CustomContentModelIT.java create mode 100644 archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/DemoComponentIT.java create mode 100644 archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptControllerTest.java create mode 100644 archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptIT.java delete mode 100644 modules/alfresco-rad/src/main/java/org/alfresco/maven/rad/RemoteRunnerWrapper.java create mode 100644 modules/alfresco-rad/src/main/java/org/alfresco/rad/SpringContextHolder.java create mode 100644 modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AbstractAlfrescoIT.java create mode 100644 modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AlfrescoTestRunner.java create mode 100644 modules/alfresco-rad/src/main/java/org/alfresco/rad/test/Remote.java create mode 100644 modules/alfresco-rad/src/main/java/org/alfresco/rad/test/RunTestWebScript.java create mode 100644 modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.desc.xml create mode 100644 modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.html.ftl create mode 100644 modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.xml.ftl create mode 100644 plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRunMojo.java create mode 100644 plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/IntegrationTestMojo.java diff --git a/archetypes/activiti-jar-archetype/src/main/resources/archetype-resources/pom.xml b/archetypes/activiti-jar-archetype/src/main/resources/archetype-resources/pom.xml index e9064b06..d9b687f7 100644 --- a/archetypes/activiti-jar-archetype/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/activiti-jar-archetype/src/main/resources/archetype-resources/pom.xml @@ -54,7 +54,7 @@ junit junit - 4.11 + 4.12 test diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/pom.xml b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/pom.xml index 5f05b294..74fcd812 100644 --- a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/pom.xml +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/pom.xml @@ -17,13 +17,6 @@ - - - ${alfresco.groupId} - alfresco-repository - - - diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/Demo.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/Demo.java index c4cb3efd..53d73e67 100644 --- a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/Demo.java +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/Demo.java @@ -1,6 +1,23 @@ #set( $symbol_pound = '#' ) #set( $symbol_dollar = '$' ) #set( $symbol_escape = '\' ) +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package ${package}.platformsample; /** diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/DemoComponent.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/DemoComponent.java index 9be2dbeb..922d677f 100644 --- a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/DemoComponent.java +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/DemoComponent.java @@ -1,22 +1,23 @@ #set($symbol_pound='#') #set($symbol_dollar='$') #set($symbol_escape='\' ) -/* -Licensed to the Apache Software Foundation (ASF) under one or more -contributor license agreements. See the NOTICE file distributed with -this work for additional information regarding copyright ownership. -The ASF licenses this file to You under the Apache License, Version 2.0 -(the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package ${package}.platformsample; import org.alfresco.repo.module.AbstractModuleComponent; @@ -56,7 +57,7 @@ public class DemoComponent extends AbstractModuleComponent { protected void executeInternal() throws Throwable { System.out.println("DemoComponent has been executed"); logger.debug("Test debug logging. Congratulation your JAR Module is working"); - logger.info("This is only for information purposed. Better remove me from the log in Production"); + logger.info("This is only for information purposes. Better remove me from the log in Production"); } /** diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/HelloWorldWebScript.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/HelloWorldWebScript.java index a853c21e..8715faf6 100644 --- a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/HelloWorldWebScript.java +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/java/platformsample/HelloWorldWebScript.java @@ -1,22 +1,23 @@ #set($symbol_pound='#') #set($symbol_dollar='$') #set($symbol_escape='\' ) -/* -Licensed to the Apache Software Foundation (ASF) under one or more -contributor license agreements. See the NOTICE file distributed with -this work for additional information regarding copyright ownership. -The ASF licenses this file to You under the Apache License, Version 2.0 -(the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package ${package}.platformsample; import org.springframework.extensions.webscripts.Cache; diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/resources/alfresco/module/__artifactId__/context/service-context.xml b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/resources/alfresco/module/__artifactId__/context/service-context.xml index c0933304..b8871e4f 100644 --- a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/resources/alfresco/module/__artifactId__/context/service-context.xml +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/main/resources/alfresco/module/__artifactId__/context/service-context.xml @@ -22,15 +22,15 @@ - + - + - + diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/CustomContentModelIT.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/CustomContentModelIT.java new file mode 100644 index 00000000..5769e654 --- /dev/null +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/CustomContentModelIT.java @@ -0,0 +1,191 @@ +#set($symbol_pound='#') +#set($symbol_dollar='$') +#set($symbol_escape='\' ) +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ${package}.platformsample; + +import org.alfresco.model.ContentModel; +import org.alfresco.rad.test.AbstractAlfrescoIT; +import org.alfresco.rad.test.AlfrescoTestRunner; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.io.IOUtils; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Integration Test sample for a custom content model. + * See {@link DemoComponentIT} for more info. + * + * @author martin.bergljung@alfresco.com + * @since 3.0 + */ +@RunWith(value = AlfrescoTestRunner.class) +public class CustomContentModelIT extends AbstractAlfrescoIT { + private static final String ACME_MODEL_NS = "{http://www.acme.org/model/content/1.0}"; + private static final String ACME_MODEL_LOCALNAME = "contentModel"; + private static final String ACME_DOCUMENT_TYPE = "document"; + private static final String ACME_SECURITY_CLASSIFIED_ASPECT = "securityClassified"; + private static final String ACME_DOCUMENT_ID_PROPNAME = "documentId"; + + @Test + public void testCustomContentModelPresence() { + Collection allContentModels = getServiceRegistry().getDictionaryService().getAllModels(); + QName customContentModelQName = createQName(ACME_MODEL_LOCALNAME); + assertTrue("Custom content model " + customContentModelQName.toString() + + " is not present", allContentModels.contains(customContentModelQName)); + } + + @Test + public void testCreateAcmeDocument() { + // Create the ACME Doc file + QName type = createQName(ACME_DOCUMENT_TYPE); + String textContent = "Hello World!"; + String documentId = "DOC001"; + Map nodeProperties = new HashMap<>(); + nodeProperties.put(createQName(ACME_DOCUMENT_ID_PROPNAME), documentId); + nodeProperties.put(createQName("securityClassification"), "Company Confidential"); + NodeRef nodeRef = createNode("AcmeFile.txt", type, nodeProperties); + addFileContent(nodeRef, textContent); + + // Add an Aspect to the file (could be a custom aspect...) + Map aspectProperties = new HashMap<>(); + aspectProperties.put(ContentModel.PROP_TITLE, "Some Doc Title"); + aspectProperties.put(ContentModel.PROP_DESCRIPTION, "Some Doc Description"); + getServiceRegistry().getNodeService().addAspect(nodeRef, ContentModel.ASPECT_TITLED, aspectProperties); + + // Assert that the file is created correctly + assertEquals("Invalid type", type, getServiceRegistry().getNodeService().getType(nodeRef)); + assertTrue("Missing security aspect", + getServiceRegistry().getNodeService().hasAspect(nodeRef, createQName(ACME_SECURITY_CLASSIFIED_ASPECT))); + assertTrue("Missing titled aspect", + getServiceRegistry().getNodeService().hasAspect(nodeRef, ContentModel.ASPECT_TITLED)); + assertEquals("Invalid property value", documentId, + getServiceRegistry().getNodeService().getProperty(nodeRef, createQName(ACME_DOCUMENT_ID_PROPNAME))); + readTextContent(nodeRef).equals(textContent); + + // Clean up node + if (nodeRef != null) { + getServiceRegistry().getNodeService().deleteNode(nodeRef); + } + } + + /** + * ==================== Helper Methods ============================================================================ + */ + + /** + * Create a QName for the ACME content model + * + * @param localname the local content model name without namespace specified + * @return the full ACME QName including namespace + */ + private QName createQName(String localname) { + return QName.createQName(ACME_MODEL_NS + localname); + } + + /** + * Create a new node, such as a file or a folder, with passed in type and properties + * + * @param name the name of the file or folder + * @param type the content model type + * @param properties the properties from the content model + * @return the Node Reference for the newly created node + */ + private NodeRef createNode(String name, QName type, Map properties) { + NodeRef parentFolderNodeRef = getCompanyHomeNodeRef(); + QName associationType = ContentModel.ASSOC_CONTAINS; + QName associationQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName(name)); + properties.put(ContentModel.PROP_NAME, name); + ChildAssociationRef parentChildAssocRef = getServiceRegistry().getNodeService().createNode( + parentFolderNodeRef, associationType, associationQName, type, properties); + + return parentChildAssocRef.getChildRef(); + } + + /** + * Add some text content to a file node + * + * @param nodeRef the node reference for the file that should have some text content added to it + * @param fileContent the text content + */ + private void addFileContent(NodeRef nodeRef, String fileContent) { + boolean updateContentPropertyAutomatically = true; + ContentWriter writer = getServiceRegistry().getContentService().getWriter(nodeRef, ContentModel.PROP_CONTENT, + updateContentPropertyAutomatically); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + writer.putContent(fileContent); + } + + /** + * Read text content for passed in file Node Reference + * + * @param nodeRef the node reference for a file containing text + * @return the text content + */ + private String readTextContent(NodeRef nodeRef) { + ContentReader reader = getServiceRegistry().getContentService().getReader(nodeRef, ContentModel.PROP_CONTENT); + if (reader == null) { + return ""; // Maybe it was a folder after all + } + + InputStream is = reader.getContentInputStream(); + try { + return IOUtils.toString(is, "UTF-8"); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + } + + /** + * Get the node reference for the /Company Home top folder in Alfresco. + * Use the standard node locator service. + * + * @return the node reference for /Company Home + */ + private NodeRef getCompanyHomeNodeRef() { + return getServiceRegistry().getNodeLocatorService().getNode(CompanyHomeNodeLocator.NAME, null, null); + } +} diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/DemoComponentIT.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/DemoComponentIT.java new file mode 100644 index 00000000..3d18d068 --- /dev/null +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/DemoComponentIT.java @@ -0,0 +1,73 @@ +#set($symbol_pound='#') +#set($symbol_dollar='$') +#set($symbol_escape='\' ) +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ${package}.platformsample; + +import org.alfresco.rad.test.AbstractAlfrescoIT; +import org.alfresco.rad.test.AlfrescoTestRunner; +import org.alfresco.rad.test.Remote; +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Integration Test of the DemoComponent using the Alfresco Test Runner. + * The Alfresco Test Runner (i.e. AlfrescoTestRunner.class) will check if it is running in an Alfresco instance, + * if so it will execute normally locally. On the other hand, if it detects no + * Alfresco Spring context, then it will make a call to a custom Web Script that + * will execute this test in the running container remotely. The remote location is + * determined by the @Remote config. + * + * @author martin.bergljung@alfresco.com + * @since 3.0 + */ +@RunWith(value = AlfrescoTestRunner.class) +// Specifying the remote endpoint is not required, it +// will default to http://localhost:8080/alfresco if +// not provided. This shows the syntax but simply +// sets the value back to the default value. +@Remote(endpoint = "http://localhost:8080/alfresco") +public class DemoComponentIT extends AbstractAlfrescoIT { + + @Test + public void testGetCompanyHome() { + DemoComponent demoComponent = (DemoComponent) getApplicationContext().getBean("org.alfresco.test.DemoComponent"); + NodeRef companyHome = demoComponent.getCompanyHome(); + assertNotNull(companyHome); + String companyHomeName = (String) getServiceRegistry().getNodeService().getProperty( + companyHome, ContentModel.PROP_NAME); + assertNotNull(companyHomeName); + assertEquals("Company Home", companyHomeName); + } + + @Test + public void testChildNodesCount() { + DemoComponent demoComponent = (DemoComponent) getApplicationContext().getBean("org.alfresco.test.DemoComponent"); + NodeRef companyHome = demoComponent.getCompanyHome(); + int childNodeCount = demoComponent.childNodesCount(companyHome); + assertNotNull(childNodeCount); + // There are 7 folders by default under Company Home + assertEquals(7, childNodeCount); + } +} \ No newline at end of file diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptControllerTest.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptControllerTest.java new file mode 100644 index 00000000..d0813fe4 --- /dev/null +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptControllerTest.java @@ -0,0 +1,56 @@ +#set($symbol_pound='#') +#set($symbol_dollar='$') +#set($symbol_escape='\' ) +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ${package}.platformsample; + +import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.extensions.webscripts.*; + +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Unit testing the Web Script Java Controller + * + * @author martin.bergljung@alfresco.com + * @version 1.0 + * @since 3.0 + */ +public class HelloWorldWebScriptControllerTest { + + @Test + public void testController() { + WebScriptRequest req = Mockito.mock(WebScriptRequest.class); + Status status = Mockito.mock(Status.class); + Cache cache = Mockito.mock(Cache.class); + + String helloPropName = "fromJava"; + String helloPropExpectedValue = "HelloFromJava"; + HelloWorldWebScript ws = new HelloWorldWebScript(); + Map model = ws.executeImpl(req, status, cache); + + assertNotNull("Response from Web Script Java Controller is null", model); + assertEquals("Incorrect Web Script Java Controller Response", + helloPropExpectedValue, model.get(helloPropName)); + } +} \ No newline at end of file diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptIT.java b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptIT.java new file mode 100644 index 00000000..9d993c62 --- /dev/null +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/__rootArtifactId__-platform-jar/src/test/java/platformsample/HelloWorldWebScriptIT.java @@ -0,0 +1,75 @@ +#set($symbol_pound='#') +#set($symbol_dollar='$') +#set($symbol_escape='\' ) +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ${package}.platformsample; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Integration Test (IT) for Hello World web script. + * + * @author martin.bergljung@alfresco.com + * @version 1.0 + * @since 3.0 + */ +public class HelloWorldWebScriptIT { + @Test + public void testWebScriptCall() throws Exception { + String webscriptURL = "http://localhost:8080/alfresco/service/sample/helloworld"; + String expectedResponse = "Message: 'Hello from JS!' 'HelloFromJava'"; + + // Login credentials for Alfresco Repo + CredentialsProvider provider = new BasicCredentialsProvider(); + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); + provider.setCredentials(AuthScope.ANY, credentials); + + // Create HTTP Client with credentials + CloseableHttpClient httpclient = HttpClientBuilder.create() + .setDefaultCredentialsProvider(provider) + .build(); + + // Execute Web Script call + try { + HttpGet httpget = new HttpGet(webscriptURL); + HttpResponse httpResponse = httpclient.execute(httpget); + assertEquals("Incorrect HTTP Response Status", + HttpStatus.SC_OK, httpResponse.getStatusLine().getStatusCode()); + HttpEntity entity = httpResponse.getEntity(); + assertNotNull("Response from Web Script is null", entity); + assertEquals("Incorrect Web Script Response", expectedResponse, EntityUtils.toString(entity)); + } finally { + httpclient.close(); + } + } +} \ No newline at end of file diff --git a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/pom.xml b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/pom.xml index 60d5d976..e65510a4 100644 --- a/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/pom.xml +++ b/archetypes/alfresco-allinone-archetype/src/main/resources/archetype-resources/pom.xml @@ -59,6 +59,52 @@ 1.7 + + + + + junit + junit + 4.12 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + org.apache.httpcomponents + httpclient + 4.5.2 + test + + + + + ${alfresco.groupId} + alfresco-repository + + + + + org.springframework + spring-context + 3.2.17.RELEASE + test + + + + + org.alfresco.maven + alfresco-rad + ${alfresco.sdk.version} + test + + + - + - + - + diff --git a/modules/alfresco-rad/pom.xml b/modules/alfresco-rad/pom.xml index 234b62ae..f3c28451 100644 --- a/modules/alfresco-rad/pom.xml +++ b/modules/alfresco-rad/pom.xml @@ -5,7 +5,8 @@ jar Rapid Application Development Support - SDK module for Rapid Development support + SDK module for Rapid Development support, such as Alfresco JUnit runner + org.alfresco.maven alfresco-sdk-aggregator @@ -13,116 +14,29 @@ ../../pom.xml - - ${project.build.directory}/pg-dialect-tmp - - - - com.tradeshift - junit-remote - 3 - jar - - - servlet-api - javax.servlet - - - - - - org.springframework - spring-test - 3.0.6.RELEASE - jar - - - - - - - + + org.alfresco + alfresco-repository + ${alfresco.community.default.version} + provided + - - - - - - --> - - - + + + org.springframework + spring-context + 3.2.17.RELEASE + + + + + junit + junit + 4.12 + + + diff --git a/modules/alfresco-rad/src/main/java/org/alfresco/maven/rad/RemoteRunnerWrapper.java b/modules/alfresco-rad/src/main/java/org/alfresco/maven/rad/RemoteRunnerWrapper.java deleted file mode 100644 index fdc21a3f..00000000 --- a/modules/alfresco-rad/src/main/java/org/alfresco/maven/rad/RemoteRunnerWrapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.alfresco.maven.rad; - -import com.tradeshift.test.remote.RemoteServer; - -public class RemoteRunnerWrapper implements Runnable { - - public void run() { - try { - RemoteServer.main(new String []{}); - } catch (Exception e) { - System.out.println("Could not start JUnit remoteServer because of: " + e.getMessage()); - } - - } - -} diff --git a/modules/alfresco-rad/src/main/java/org/alfresco/rad/SpringContextHolder.java b/modules/alfresco-rad/src/main/java/org/alfresco/rad/SpringContextHolder.java new file mode 100644 index 00000000..1e9a4dbd --- /dev/null +++ b/modules/alfresco-rad/src/main/java/org/alfresco/rad/SpringContextHolder.java @@ -0,0 +1,69 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.alfresco.rad; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * This Spring bean is aware of the application context in which + * it is initialized. + * + * @author martin.bergljung@alfresco.com + * @since 3.0 + */ +public class SpringContextHolder implements ApplicationContextAware { + + /** + * The instance of SpringContextHolder + */ + private static SpringContextHolder springContextHolderInstance; + + /** + * The Alfresco Spring Application Context. + */ + private ApplicationContext applicationContext; + + /** + * Default constructor. + */ + public SpringContextHolder() { + System.out.println("Initializing the SpringContextHolder class."); + springContextHolderInstance = this; + } + + /** + * Return the singleton instance + * + * @return + */ + public static SpringContextHolder Instance() { + return springContextHolderInstance; + } + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + System.out.println("Setting current Spring Application Context in SpringContextHolder class."); + this.applicationContext = applicationContext; + } + + public ApplicationContext getApplicationContext() { + return applicationContext; + } + +} diff --git a/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AbstractAlfrescoIT.java b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AbstractAlfrescoIT.java new file mode 100644 index 00000000..4fc0ccdb --- /dev/null +++ b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AbstractAlfrescoIT.java @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.rad.test; + +import org.alfresco.rad.SpringContextHolder; +import org.alfresco.service.ServiceRegistry; +import org.junit.Rule; +import org.junit.rules.MethodRule; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; +import org.springframework.context.ApplicationContext; + +/** + * Abstract Integration Test class to be used + * by Alfresco Integration Tests. Gives access to + * Alfresco Spring Application context and the + * {@link ServiceRegistry} that should be used when + * accessing Alfresco Services. + * + * @author martin.bergljung@alfresco.com + * @since 3.0 + */ +public abstract class AbstractAlfrescoIT { + private ApplicationContext applicationContext = null; + private ServiceRegistry serviceRegistry = null; + + /** + * Print the test we are currently running, useful if the test is running remotely + * and we don't see the server logs + */ + @Rule + public MethodRule testAnnouncer = new MethodRule() { + @Override + public Statement apply(Statement base, FrameworkMethod method, Object target) { + System.out.println("Running " + getClassName() + " Integration Test: " + method.getName() + "()"); + return base; + } + }; + + protected String getClassName() { + Class enclosingClass = getClass().getEnclosingClass(); + if (enclosingClass != null) { + return enclosingClass.getName(); + } else { + return getClass().getName(); + } + } + + protected ApplicationContext getApplicationContext() { + if (applicationContext == null) { + SpringContextHolder springContextHolder = SpringContextHolder.Instance(); + if (springContextHolder != null) { + applicationContext = springContextHolder.getApplicationContext(); + } + } + + return applicationContext; + } + + protected ServiceRegistry getServiceRegistry() { + if (serviceRegistry == null) { + ApplicationContext ctx = getApplicationContext(); + if (ctx != null) { + Object bean = ctx.getBean("ServiceRegistry"); + if (bean != null && bean instanceof ServiceRegistry) { + serviceRegistry = (ServiceRegistry) bean; + } + } + } + + return serviceRegistry; + } +} \ No newline at end of file diff --git a/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AlfrescoTestRunner.java b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AlfrescoTestRunner.java new file mode 100644 index 00000000..a2eedf99 --- /dev/null +++ b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/AlfrescoTestRunner.java @@ -0,0 +1,249 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.alfresco.rad.test; + +import org.alfresco.rad.SpringContextHolder; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.Ignore; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.*; + +/** + * This is a JUnit test runner that is designed to work with an Alfresco repository. + * It detects if it's executing a test inside of a running Alfresco instance. If that + * is the case the tests are all run normally. If however the test is being run from + * outside the repository, from the maven command line or from an IDE + * such as IntelliJ or STS/Eclipse for example, then instead of running the actual + * test an HTTP request is made to a Web Script in a running Alfresco instance. This + * Web Script runs the test and returns enough information to this class so we can + * emulate having run the test locally. + *

+ * By doing this, we are able to create Integration Tests (IT) using standard JUnit + * capabilities. These can then be run from our IDEs with the associated visualizations, + * support for re-running failed tests, etc. + *

+ * Integration testing framework donated by Zia Consulting + * + * @author Bindu Wavell + * @author martin.bergljung@alfresco.com (some editing) + * @since 3.0 + */ +public class AlfrescoTestRunner extends BlockJUnit4ClassRunner { + public static final String SUCCESS = "SUCCESS"; + public static final String FAILURE = "FAILURE"; + + public AlfrescoTestRunner(Class klass) throws InitializationError { + super(klass); + } + + public static String serializableToString(Serializable serializable) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(serializable); + oos.close(); + + String string = Base64.encodeBase64URLSafeString(baos.toByteArray()); + + return string; + } + + @Override + protected void runChild(FrameworkMethod method, RunNotifier notifier) { + if (areWeRunningInAlfresco()) { + // Just run the test as normally + super.runChild(method, notifier); + } else { + // We are not running in an Alfresco Server, we need to call one and have it execute the test... + Description desc = describeChild(method); + if (method.getAnnotation(Ignore.class) != null) { + notifier.fireTestIgnored(desc); + } else { + callProxiedChild(method, notifier, desc); + } + } + } + + /** + * Call a remote Alfresco server and have the test run there. + * + * @param method the test method to run + * @param notifier + * @param desc + */ + protected void callProxiedChild(FrameworkMethod method, RunNotifier notifier, Description desc) { + notifier.fireTestStarted(desc); + + String className = method.getMethod().getDeclaringClass().getCanonicalName(); + String methodName = method.getName(); + if (null != methodName) { + className += "#" + methodName; + } + + // Login credentials for Alfresco Repo + // TODO: Maybe configure credentials in props... + CredentialsProvider provider = new BasicCredentialsProvider(); + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin"); + provider.setCredentials(AuthScope.ANY, credentials); + + // Create HTTP Client with credentials + CloseableHttpClient httpclient = HttpClientBuilder.create() + .setDefaultCredentialsProvider(provider) + .build(); + + // Create the GET Request for the Web Script that will run the test + String testWebScriptUrl = "/service/testing/test.xml?clazz=" + className.replace("#", "%23"); + System.out.println("AlfrescoTestRunner: Invoking Web Script for test execution: " + testWebScriptUrl); + HttpGet get = new HttpGet(getContextRoot(method) + testWebScriptUrl); + + try { + // Send proxied request and read response + HttpResponse resp = httpclient.execute(get); + InputStream is = resp.getEntity().getContent(); + InputStreamReader ir = new InputStreamReader(is); + BufferedReader br = new BufferedReader(ir); + String body = ""; + String line; + while ((line = br.readLine()) != null) { + body += line + "\n"; + } + + // Process response + if (body.length() > 0) { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = null; + dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(new InputSource(new StringReader(body))); + + Element root = doc.getDocumentElement(); + NodeList results = root.getElementsByTagName("result"); + if (null != results && results.getLength() > 0) { + String result = results.item(0).getFirstChild().getNodeValue(); + if (SUCCESS.equals(result)) { + notifier.fireTestFinished(desc); + } else { + boolean failureFired = false; + NodeList throwableNodes = root.getElementsByTagName("throwable"); + for (int tid = 0; tid < throwableNodes.getLength(); tid++) { + String throwableBody = null; + Object object = null; + Throwable throwable = null; + throwableBody = throwableNodes.item(tid).getFirstChild().getNodeValue(); + if (null != throwableBody) { + try { + object = objectFromString(throwableBody); + } catch (ClassNotFoundException e) { + } + if (null != object && object instanceof Throwable) { + throwable = (Throwable) object; + } + } + if (null == throwable) { + throwable = new Throwable("Unable to process exception body: " + throwableBody); + } + + notifier.fireTestFailure(new Failure(desc, throwable)); + failureFired = true; + } + if (!failureFired) { + notifier.fireTestFailure(new Failure(desc, new Throwable( + "There was an error but we can't figure out what it was, sorry!"))); + } + } + } else { + notifier.fireTestFailure(new Failure(desc, new Throwable( + "Unable to process response for proxied test request: " + body))); + } + } else { + notifier.fireTestFailure(new Failure(desc, new Throwable( + "Attempt to proxy test into running Alfresco instance failed, no response received"))); + } + } catch (IOException e) { + notifier.fireTestFailure(new Failure(desc, e)); + } catch (ParserConfigurationException e) { + notifier.fireTestFailure(new Failure(desc, e)); + } catch (SAXException e) { + notifier.fireTestFailure(new Failure(desc, e)); + } finally { + try { + httpclient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + protected static Object objectFromString(String string) throws IOException, ClassNotFoundException { + byte[] buffer = Base64.decodeBase64(string); + ObjectInputStream ois = new ObjectInputStream( + new ByteArrayInputStream(buffer)); + Object object = ois.readObject(); + ois.close(); + return object; + } + + /** + * Check if we are running this test in an Alfresco server instance. + * + * @return true if we are running in an Alfresco server + */ + protected boolean areWeRunningInAlfresco() { + Object contextHolder = SpringContextHolder.Instance(); + return (contextHolder != null); + } + + /** + * Check the @Remote config on the test class to see where the + * Alfresco Repo is running + * + * @param method + * @return + */ + protected String getContextRoot(FrameworkMethod method) { + Class declaringClass = method.getMethod().getDeclaringClass(); + boolean annotationPresent = declaringClass.isAnnotationPresent(Remote.class); + if (annotationPresent) { + Remote annotation = declaringClass.getAnnotation(Remote.class); + return annotation.endpoint(); + } + + return "http://localhost:8080/alfresco"; + } + +} \ No newline at end of file diff --git a/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/Remote.java b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/Remote.java new file mode 100644 index 00000000..0a1cfd3e --- /dev/null +++ b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/Remote.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.rad.test; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * By default the ${@link AlfrescoTestRunner} will attempt to find a + * running Alfresco instance at http://localhost:8080/alfresco + * This annotation can be applied to a test class to have the + * proxy calls go to a different host/port. + *

+ * Integration testing framework donated by Zia Consulting. + * + * @author Bindu Wavell + * @since 3.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Remote { + + String endpoint() default "http://localhost:8080/alfresco"; + +} diff --git a/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/RunTestWebScript.java b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/RunTestWebScript.java new file mode 100644 index 00000000..bd060a6f --- /dev/null +++ b/modules/alfresco-rad/src/main/java/org/alfresco/rad/test/RunTestWebScript.java @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.rad.test; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.junit.runner.JUnitCore; +import org.junit.runner.Request; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.springframework.extensions.webscripts.Cache; +import org.springframework.extensions.webscripts.DeclarativeWebScript; +import org.springframework.extensions.webscripts.Status; +import org.springframework.extensions.webscripts.WebScriptRequest; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This Web Script works in consort with the ${@link AlfrescoTestRunner}. When a test is run from an IDE or + * command line, the Alfresco test runner sends a proxied request to perform the test to this script. This runs + * the test and wraps the results up so that the test initiator can be fooled into thinking they are + * running the tests locally. + *

+ * Integration testing framework donated by Zia Consulting. + * + * @author Bindu Wavell + * @author martin.bergljung@alfresco.com (some editing) + * @since 3.0 + */ +public class RunTestWebScript extends DeclarativeWebScript { + + @Override + protected Map executeImpl(WebScriptRequest req, Status status, Cache cache) { + System.out.println("RunTestWebScript: Start executing ..."); + String result = AlfrescoTestRunner.FAILURE; + String clazzAndMethod = null; + String clazz = null; // Test class + String method = null; // Test method + Result junitRunnerResult = null; + + // Example invocation: + // /service/testing/test.xml?clazz=org.alfresco.test.platformsample.DemoComponentIT%23testChildNodesCount + + // First, try and get the test class, including method, from a template var, i.e. /clazz/{class%23method} + clazzAndMethod = req.getServiceMatch().getTemplateVars().get("clazz"); + if (clazzAndMethod == null) { + // Not found in template var, try parameter, i.e. ?clazz={class%23method} + clazzAndMethod = req.getParameter("clazz"); + } + System.out.println("RunTestWebScript: clazzAndMethod = " + clazzAndMethod); + + // Do we have a test class and method now? + if (clazzAndMethod == null) { + // No, set class and method as not provided + clazzAndMethod = "not provided"; + } else { + // We got a test class and method, proceed + Class c = null; + // Split class and method on %23 = # + String[] clazzAndMethodArray = clazzAndMethod.split("#"); + if (clazzAndMethodArray.length > 1) { + clazz = clazzAndMethodArray[0]; + method = clazzAndMethodArray[1]; + } + System.out.println("RunTestWebScript: [clazz=" + clazz + "][method=" + method + "]"); + + try { + // Load the Java class that will be run by JUnit + c = Class.forName(clazz); + } catch (ClassNotFoundException ex) { + throw new AlfrescoRuntimeException("Could not find test class: " + clazzAndMethod); + } + + // See if JUnit should run test for whole class, or just specified method + if (method == null) { + // No method, run all tests in class + junitRunnerResult = JUnitCore.runClasses(c); + } else { + // We got one specific test method to run + Request jreq = Request.method(c, method); + junitRunnerResult = new JUnitCore().run(jreq); + } + + // Check if test was successful + if (junitRunnerResult.wasSuccessful()) { + result = AlfrescoTestRunner.SUCCESS; + } + } + + // Set up model to send to Web Script template + // + // What test did we run + Map model = new HashMap(); + if (method == null) { + // We don't have a test method... + model.put("test", clazzAndMethod); + } else { + model.put("test", clazzAndMethod + "#" + method); + } + // Overall Alfresco Test runner result + model.put("result", result); + // JUnit Runner stats + if (junitRunnerResult != null) { + model.put("resultObject", junitRunnerResult); + model.put("failures", junitRunnerResult.getFailures()); + model.put("failureCount", junitRunnerResult.getFailureCount()); + model.put("ignoreCount", junitRunnerResult.getIgnoreCount()); + model.put("runCount", junitRunnerResult.getRunCount()); + model.put("runTime", junitRunnerResult.getRunTime()); + List throwables = new ArrayList<>(); + if (null != junitRunnerResult.getFailures()) { + for (Failure failure : junitRunnerResult.getFailures()) { + try { + throwables.add(AlfrescoTestRunner.serializableToString(failure.getException())); + } catch (IOException e) { + try { + throwables.add(AlfrescoTestRunner.serializableToString( + "Unable to serialize exception.")); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + } + + model.put("throwables", throwables); + model.put("wasSuccessful", junitRunnerResult.wasSuccessful()); + } + + System.out.println("RunTestWebScript: model = " + model); + System.out.println("RunTestWebScript: Stopped executing"); + + return model; + } +} \ No newline at end of file diff --git a/modules/alfresco-rad/src/main/resources/alfresco/extension/rad-context.xml b/modules/alfresco-rad/src/main/resources/alfresco/extension/rad-context.xml index bf0a37ea..77101d56 100644 --- a/modules/alfresco-rad/src/main/resources/alfresco/extension/rad-context.xml +++ b/modules/alfresco-rad/src/main/resources/alfresco/extension/rad-context.xml @@ -1,29 +1,33 @@ + Copyright (C) 2017 Alfresco Software Limited. + + This file is part of the Alfresco SDK project. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> - - - - - + + + + + + - diff --git a/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.desc.xml b/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.desc.xml new file mode 100644 index 00000000..75b2ad12 --- /dev/null +++ b/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.desc.xml @@ -0,0 +1,37 @@ + + + + Perform Test + Run integration test in Alfresco context + /testing/test?clazz={clazz} + any + internal + user + Alfresco SDK + + false + false + + + html + html + \ No newline at end of file diff --git a/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.html.ftl b/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.html.ftl new file mode 100644 index 00000000..a0021e8b --- /dev/null +++ b/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.html.ftl @@ -0,0 +1,34 @@ + + + ${test?html} + + + +

Integration Test: ${test?html}

+
Result: ${result}
+<#if failures??> + <#list failures as failure> +
${failure.getTestHeader()?html}
+ + +
+ + + + \ No newline at end of file diff --git a/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.xml.ftl b/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.xml.ftl new file mode 100644 index 00000000..c3e95303 --- /dev/null +++ b/modules/alfresco-rad/src/main/resources/alfresco/extension/templates/webscripts/org/alfresco/rad/test/runtest.get.xml.ftl @@ -0,0 +1,27 @@ + + + ${test?html} + ${result?html} +<#if failures??> + + <#list failures as failure> + ${failure.getTrace()?html} + ${failure.getException()?html} + ${failure.getMessage()?html} + ${failure.getTestHeader()?html} + + + + ${failureCount?html} + ${ignoreCount?html} + ${runCount?html} + ${runTime?html} +<#if throwables??> + + <#list throwables as throwable> + ${throwable?html} + + + + ${wasSuccessful?string} + \ No newline at end of file diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRefreshWebappMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRefreshWebappMojo.java index fb046621..bb236ef1 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRefreshWebappMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRefreshWebappMojo.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Alfresco Software Limited. + * Copyright (C) 2017 Alfresco Software Limited. *

* This file is part of the Alfresco SDK. *

diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRunMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRunMojo.java new file mode 100644 index 00000000..903c69b2 --- /dev/null +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/AbstractRunMojo.java @@ -0,0 +1,1391 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.alfresco.maven.plugin; + +import org.alfresco.maven.plugin.config.ModuleDependency; +import org.alfresco.maven.plugin.config.TomcatDependency; +import org.alfresco.maven.plugin.config.TomcatWebapp; +import org.apache.commons.lang.StringUtils; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Dependency; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.BuildPluginManager; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.*; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.FileUtils; +import org.zeroturnaround.zip.ZipUtil; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.twdata.maven.mojoexecutor.MojoExecutor.*; + + +/** + * Abstract runner component used by both the standard runner that blocks after startup and the + * integration test runner that stops container after each sub-project execution. + * + * @author ole.hejlskov, martin.bergljung + * @version 1.0 + * @since 3.0 + */ +public abstract class AbstractRunMojo extends AbstractMojo { + public static final String MAVEN_DEPENDENCY_PLUGIN_VERSION = "2.10"; + public static final String MAVEN_INSTALL_PLUGIN_VERSION = "2.5.2"; + public static final String MAVEN_REPLACER_PLUGIN_VERSION = "1.5.3"; + public static final String MAVEN_RESOURCE_PLUGIN_VERSION = "2.7"; + public static final String MAVEN_TOMCAT7_PLUGIN_VERSION = "2.2"; + public static final String MAVEN_BUILD_HELPER_PLUGIN_VERSION = "1.12"; + + public static final String PLATFORM_WAR_PREFIX_NAME = "platform"; + public static final String SHARE_WAR_PREFIX_NAME = "share"; + public static final String ACTIVITI_APP_WAR_PREFIX_NAME = "activitiApp"; + + public static final String ALFRESCO_ENTERPRISE_EDITION = "enterprise"; + public static final String ALFRESCO_COMMUNITY_EDITION = "community"; + + @Component + protected MavenProject project; + + @Component + protected MavenSession session; + + @Component + protected BuildPluginManager pluginManager; + + /** + * The following properties that start with 'maven.' are used to control the + * Alfresco Maven plugin itself. + *

+     * For example:
+     *    {@code
+     *      
+     *          org.alfresco.maven.plugin
+     *          alfresco-maven-plugin
+     *          3.0.0
+     *          
+     *              community
+     *              true
+     *              true
+     *              true
+     *              false*
+     *              
+     *                  
+     *                      ${alfresco.groupId}
+     *                      alfresco-share-services
+     *                      ${alfresco.share.version}
+     *                      amp
+     *                  
+     *              
+     *          
+     *      
+     *    }
+     * 
+ */ + + /** + * Switch to enable/disable the Apache Solr 4 web application when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enableSolr", defaultValue = "true") + protected boolean enableSolr; + + /** + * Switch to enable/disable the H2 database when running embedded Tomcat. + * This also brings in the needed H2 database scripts. + */ + @Parameter(property = "maven.alfresco.enableH2", defaultValue = "false") + protected boolean enableH2; + + /** + * Switch to enable/disable the MySQL database when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enableMySQL", defaultValue = "false") + protected boolean enableMySQL; + + /** + * Switch to enable/disable the PostgreSQL database when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enablePostgreSQL", defaultValue = "false") + protected boolean enablePostgreSQL; + + /** + * Switch to enable/disable the Enterprise database (such as Oracle or MS SQL Server) when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enableEnterpriseDb", defaultValue = "false") + protected boolean enableEnterpriseDb; + + /** + * Switch to enable/disable the Platform/Repository (alfresco.war) when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enablePlatform", defaultValue = "true") + protected boolean enablePlatform; + + /** + * Switch to enable/disable the Share (share.war) when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enableShare", defaultValue = "true") + protected boolean enableShare; + + /** + * Enables the use of custom context path for the Share webapp. + * Some solution integrators uses a custom context path for Share in their projects. + * This property enables them to continue to do that in SDK 3 without having to completely override the + * Maven Tomcat plugin configuration, or not use it at all and go back the good old runner project again... + */ + @Parameter(property = "maven.alfresco.shareContextPath", defaultValue = "/share") + protected String shareContextPath; + + /** + * Share Log4j.properties configuration cannot be customized via extension + * put on the classpath, like on the platform side. + * So we need to override the log4j.properties in share/WEB-INF/classes + * to be able to log from custom code. + * This property can be used to turn off this overriding, to produce a WAR with + * the standard Share log4j.properties file. + */ + @Parameter(property = "maven.alfresco.useCustomShareLog4jConfig", defaultValue = "true") + protected boolean useCustomShareLog4jConfig; + + /** + * Switch to enable/disable the Alfresco REST API Explorer (api-explorer.war) when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enableApiExplorer", defaultValue = "false") + protected boolean enableApiExplorer; + + /** + * Switch to enable/disable Alfresco Activiti Workflow Engine (activiti-app.war) when running embedded Tomcat. + * This contains the Alfresco Activiti webapp, including the workflow engine. + * This webapp is also the user interface for people involved in the task and processes + * running in the Activiti engine. + * You also use this webapp to create and manage process definitions, and to display and define analytics + * reports on users' tasks and processes. + */ + @Parameter(property = "maven.alfresco.enableActivitiApp", defaultValue = "false") + protected boolean enableActivitiApp; + + /** + * Switch to enable/disable Alfresco Activiti Admin (activiti-admin.war) when running embedded Tomcat. + * This contains the Alfresco Activiti Administrator webapp. You use this to administer and monitor your + * Alfresco Activiti engines. + * + */ + @Parameter(property = "maven.alfresco.enableActivitiAdmin", defaultValue = "false") + protected boolean enableActivitiAdmin; + + /** + * Switch to enable/disable test properties when running embedded Tomcat. + */ + @Parameter(property = "maven.alfresco.enableTestProperties", defaultValue = "true") + protected boolean enableTestProperties; + + /** + * Control if Tomcat 7 Plugin should be kicked off and start Apache Tomcat + */ + @Parameter(property = "maven.alfresco.startTomcat", defaultValue = "true") + protected boolean startTomcat; + + /** + * Directory containing test files that should be used when running embedded Tomcat + */ + @Parameter(property = "maven.alfresco.testFolder", defaultValue = "src/test/properties/${env}") + protected String testFolder; + + /** + * Test files in testFolder that should be included when running embedded Tomcat + */ + @Parameter(property = "maven.alfresco.testInclude", defaultValue = "**") + protected String testInclude; + + /** + * JARs and AMPs that should be overlayed/applied to the Platform/Repository WAR (i.e. alfresco.war) + */ + @Parameter(property = "maven.alfresco.platform.modules", defaultValue = "") + protected List platformModules; + + /** + * JARs and AMPs that should be overlayed/applied to the Share WAR (i.e. share.war) + */ + @Parameter(property = "maven.alfresco.share.modules", defaultValue = "") + protected List shareModules; + + /** + * JARs that should be overlayed/applied to the Activiti App WAR (i.e. activiti-app.war) + */ + @Parameter(property = "maven.activiti.modules", defaultValue = "") + protected List activitiModules; + + /** + * Community Edition or Enterprise Edition? (i.e community or enterprise) + */ + @Parameter(property = "maven.alfresco.edition", defaultValue = ALFRESCO_COMMUNITY_EDITION) + protected String alfrescoEdition; + + /** + * Tomcat Dependencies that should be added to the Embedded Tomcat configuration before start. + * Normally there would not be any extra dependencies, but could be if you run an Enterprise database + * such as Oracle, for which there's no quick config, such as enableH2, enableMySQL, or enablePostgreSQL. + */ + @Parameter(property = "maven.alfresco.tomcat.dependencies", defaultValue = "") + protected List tomcatDependencies; + + /** + * System Properties to feed the Tomcat plugin before start. + * Normally there would not be any extra dependencies, but we could run a custom webapp that needed + * a custom sys prop set. + */ + @Parameter(property = "maven.alfresco.tomcat.system.properties", defaultValue = "") + protected Map tomcatSystemProperties; + + /** + * Custom webapps that should be deployed to the embedded Tomcat engine. + * Normally there would not be any extra webapps, but we could run a bigger project that uses + * some custom webapp. + */ + @Parameter(property = "maven.alfresco.tomcat.custom.webapps", defaultValue = "") + protected List tomcatCustomWebapps; + + /** + * Maven GAV properties for standard Alfresco web applications. + */ + @Parameter(property = "alfresco.groupId", defaultValue = "org.alfresco") + protected String alfrescoGroupId; + + @Parameter(property = "activiti.groupId", defaultValue = "com.activiti") + protected String activitiGroupId; + + @Parameter(property = "alfresco.platform.war.artifactId", defaultValue = "alfresco-platform") + protected String alfrescoPlatformWarArtifactId; + + @Parameter(property = "alfresco.share.war.artifactId", defaultValue = "share") + protected String alfrescoShareWarArtifactId; + + @Parameter(property = "alfresco.solr.artifactId", defaultValue = "alfresco-solr4") + protected String alfrescoSolrArtifactId; + + @Parameter(property = "alfresco.api.explorer.artifactId", defaultValue = "api-explorer") + protected String alfrescoApiExplorerArtifactId; + + @Parameter(property = "activiti.app.war.artifactId", defaultValue = "activiti-app") + protected String activitiAppWarArtifactId; + + @Parameter(property = "activiti.admin.war.artifactId", defaultValue = "activiti-admin") + protected String activitiAdminWarArtifactId; + + @Parameter(property = "alfresco.platform.version", defaultValue = "5.2.e") + protected String alfrescoPlatformVersion; + + @Parameter(property = "alfresco.share.version", defaultValue = "5.2.d") + protected String alfrescoShareVersion; + + @Parameter(property = "alfresco.api.explorer.version", defaultValue = "5.2.e") + protected String alfrescoApiExplorerVersion; + + @Parameter(property = "activiti.version", defaultValue = "1.5.3") + protected String activitiVersion; + + /** + * Directory that contains the Alfresco Solr 4 configuration + */ + @Parameter(property = "solr.home", defaultValue = "${project.basedir}/${alfresco.data.location}/solr") + protected String solrHome; + + /** + * Maven GAV properties for customized alfresco.war, share.war, activiti-app.war + * Used by the Maven Tomcat 7 Plugin + */ + private String runnerAlfrescoGroupId; + private String runnerAlfrescoPlatformWarArtifactId; + private String runnerAlfrescoShareWarArtifactId; + private String runnerAlfrescoPlatformVersion; + private String runnerAlfrescoShareVersion; + private String runnerActivitiAppGroupId; + private String runnerActivitiAppWarArtifactId; + private String runnerActivitiAppVersion; + + /** + * The Maven environment that this mojo is executed in + */ + protected ExecutionEnvironment execEnv; + + /** + * Download and unpack the Solr 4 configuration as we don't have it in the project. + * It will reside under /alf_data_dev/solr + * + * @throws MojoExecutionException + */ + protected void unpackSolrConfig() throws MojoExecutionException { + getLog().info("Unpacking Solr config"); + + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version(MAVEN_DEPENDENCY_PLUGIN_VERSION) + ), + goal("unpack"), + configuration( + element(name("outputDirectory"), solrHome), + element(name("artifactItems"), + element(name("artifactItem"), + element(name("groupId"), alfrescoGroupId), + element(name("artifactId"), getSolrArtifactId()), + element(name("version"), alfrescoPlatformVersion), + // The Solr config is not in a special file with classifier config if <= 4.2 + isPlatformVersionLtOrEqTo42() ? element(name("classifier"), "") : element(name("classifier"), "config"), + element(name("type"), "zip") + ) + ) + ), + execEnv + ); + } + + /** + * For windows paths, convert single \ to / for the ${alfresco.solr.data.dir} path, + * by default it will be c:\bla\, we need forward slash or double backslash. + * + * @throws MojoExecutionException + */ + protected void fixSolrHomePath() throws MojoExecutionException { + getLog().info("Fix Solr Home Path to work in Windows"); + + executeMojo( + plugin( + groupId("org.codehaus.mojo"), + artifactId("build-helper-maven-plugin"), + version(MAVEN_BUILD_HELPER_PLUGIN_VERSION) + ), + goal("regex-property"), + configuration( + element(name("name"), "solrDataDir"), + element(name("value"), solrHome), + element(name("regex"), "\\\\"), + element(name("replacement"), "/"), + element(name("failIfNoMatch"), "false") + ), + execEnv + ); + } + + /** + * Replace property placeholders in configuration files for the cores, so the + * index files can be found for each core when Solr starts up. + * + * @throws MojoExecutionException + */ + protected void replaceSolrConfigProperties() throws MojoExecutionException { + getLog().info("Replacing Solr config properties"); + executeMojo( + plugin( + groupId("com.google.code.maven-replacer-plugin"), + artifactId("replacer"), + version(MAVEN_REPLACER_PLUGIN_VERSION) + ), + goal("replace"), + configuration( + element(name("regex"), "false"), + element(name("includes"), + element(name("include"), solrHome + "/archive-SpacesStore/conf/solrcore.properties"), + element(name("include"), solrHome + "/workspace-SpacesStore/conf/solrcore.properties") + ), + element(name("replacements"), + element(name("replacement"), + element(name("token"), "@@ALFRESCO_SOLR4_DATA_DIR@@"), + element(name("value"), "${solrDataDir}/index") + ) + ) + ), + execEnv + ); + } + + /** + * If we are in Alfresco version 4.2 or younger the Solr 1.0 WAR is not available as Maven artifact, just + * as part of a ZIP file, so install it locally so we can deploy from embedded tomcat + * + * @throws MojoExecutionException + */ + protected void installSolr10InLocalRepo() throws MojoExecutionException { + if (isPlatformVersionLtOrEqTo42()) { + getLog().info("Installing Solr 1.0 WAR in local Maven repo"); + + // Install the Solr 1.0 war file in local maven repo + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-install-plugin"), + version(MAVEN_INSTALL_PLUGIN_VERSION) + ), + goal("install-file"), + configuration( + element(name("file"), solrHome + "/apache-solr-1.4.1.war"), + element(name("groupId"), "${project.groupId}"), + element(name("artifactId"), getSolrArtifactId()), + element(name("version"), "${project.version}"), + element(name("packaging"), "war") + ) + , execEnv + ); + } + } + + /** + * Replaces web.xml where applicable in platform webapp (alfresco.war), + * commenting out the security-constraints. + *

+ * This is only needed for 4.2, 5.0 (5.1 handles it automatically when turning off ssl via props) + * + * @throws MojoExecutionException + */ + protected void commentOutSecureCommsInPlatformWebXml() throws MojoExecutionException { + if (isPlatformVersionGtOrEqTo51()) { + return; + } + + String webInfPath = getWarOutputDir(PLATFORM_WAR_PREFIX_NAME) + "/WEB-INF/"; + String webXmlFilePath = webInfPath + "web.xml"; + + getLog().info("Commenting out the security-constraints in " + webXmlFilePath); + + executeMojo( + plugin( + groupId("com.google.code.maven-replacer-plugin"), + artifactId("replacer"), + version(MAVEN_REPLACER_PLUGIN_VERSION) + ), + goal("replace"), + configuration( + element(name("ignoreErrors"), "true"), + element(name("file"), webXmlFilePath), + element(name("outputDir"), webInfPath), + element(name("preserveDir"), "false"), + element(name("replacements"), + element(name("replacement"), + element(name("token"), ""), + element(name("value"), ""), + element(name("value"), " -->") + ) + ) + ), + execEnv + ); + } + + /** + * Copy the different alfresco-global-*.properties files (there are one for each open source db and one for + * enterprise db config) that will be used when running Alfresco. It contains database connection parameters and + * other general configuration for Alfresco Repository (alfresco.war) + * + * @throws MojoExecutionException + */ + protected void copyAlfrescoGlobalProperties() throws MojoExecutionException { + getLog().info("Copying and filtering alfresco-global-*.properties files to target/test-classes"); + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-resources-plugin"), + version(MAVEN_RESOURCE_PLUGIN_VERSION) + ), + goal("copy-resources"), + configuration( + element(name("outputDirectory"), "${project.build.testOutputDirectory}"), + element(name("resources"), + element(name("resource"), + element(name("directory"), testFolder), + element(name("includes"), + element(name("include"), testInclude) + ), + element(name("filtering"), "true") + ) + ) + ), + execEnv + ); + } + + /** + * Rename the configured database specific alfresco-global-*.properties file to + * alfresco-global.properties so it will be used during Tomcat run. + * + * @throws MojoExecutionException + */ + protected void renameAlfrescoGlobalProperties() throws MojoExecutionException { + String alfrescoGlobalFilePath = project.getBuild().getTestOutputDirectory() + "/alfresco-global-"; + if (enableH2) { + alfrescoGlobalFilePath += "h2.properties"; + getLog().info("Renaming alfresco-global-h2.properties to alfresco-global.properties"); + } else if (enableMySQL) { + alfrescoGlobalFilePath += "mysql.properties"; + getLog().info("Renaming alfresco-global-mysql.properties to alfresco-global.properties"); + } else if (enablePostgreSQL) { + alfrescoGlobalFilePath += "postgresql.properties"; + getLog().info("Renaming alfresco-global-postgresql.properties to alfresco-global.properties"); + } else if (enableEnterpriseDb) { + alfrescoGlobalFilePath += "enterprise.properties"; + getLog().info("Renaming alfresco-global-enterprise.properties to alfresco-global.properties"); + } else { + throw new MojoExecutionException("Invalid database configuration, use enableH2, enableMySQL, " + + "enablePostgreSQL, or enabaleEnterpriseDb"); + } + + if (!FileUtils.fileExists(alfrescoGlobalFilePath)) { + throw new MojoExecutionException("Missing file: " + alfrescoGlobalFilePath + ", when converting from older " + + "SDK versions generate an SDK 3 AIO or Platform JAR project and copy " + + "alfresco-global-*.properties files from it. Then configure any custom settings from old SDK " + + "project repo/src/main/properties/local/alfresco-global.properties file in the new " + + "alfresco-global-h2.properties file, or other config file corresponding to the database you are using."); + } + + executeMojo( + plugin( + groupId("com.coderplus.maven.plugins"), + artifactId("copy-rename-maven-plugin"), + version("1.0") + ), + goal("rename"), + configuration( + element(name("sourceFile"), alfrescoGlobalFilePath), + element(name("destinationFile"), "${project.build.testOutputDirectory}/alfresco-global.properties") + ), + execEnv + ); + } + + /** + * Copy the Alfresco Enterprise license to its correct place in the Platform WAR, if it exists. + * It is not enough to have it on the test classpath, then it will start up as Trial license... + * + * @throws MojoExecutionException + */ + protected void copyAlfrescoLicense() throws MojoExecutionException { + if (alfrescoEdition.equals(ALFRESCO_COMMUNITY_EDITION)) { + getLog().info("NOT copying Alfresco Enterprise license, running Community edition"); + return; + } + + final String warOutputDir = getWarOutputDir(PLATFORM_WAR_PREFIX_NAME); + final String licDestDir = warOutputDir + "/WEB-INF/classes/alfresco/extension/license"; + + getLog().info("Copying Alfresco Enterprise license to: " + licDestDir); + + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-resources-plugin"), + version(MAVEN_RESOURCE_PLUGIN_VERSION) + ), + goal("copy-resources"), + configuration( + element(name("outputDirectory"), licDestDir), + element(name("resources"), + element(name("resource"), + element(name("directory"), "src/test/license"), + element(name("includes"), + element(name("include"), "*.lic") + ), + element(name("filtering"), "false") + ) + ) + ), + execEnv + ); + } + + /** + * Copy the Activiti Log4J Dev config into the activitiApp-war/WEB-INF/classes dir. + * + * @throws MojoExecutionException + */ + protected void copyActivitiLog4JDevConfig() throws MojoExecutionException { + final String warOutputDir = getWarOutputDir(ACTIVITI_APP_WAR_PREFIX_NAME); + final String logConfDestDir = warOutputDir + "/WEB-INF/classes"; + + getLog().info("Copying Activiti log4j-dev.properties to: " + logConfDestDir); + + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-resources-plugin"), + version(MAVEN_RESOURCE_PLUGIN_VERSION) + ), + goal("copy-resources"), + configuration( + element(name("outputDirectory"), logConfDestDir), + element(name("resources"), + element(name("resource"), + element(name("directory"), "src/test/resources"), + element(name("includes"), + element(name("include"), "log4j-dev.properties") + ), + element(name("filtering"), "true") + ) + ) + ), + execEnv + ); + } + + /** + * Copy a custom Share Log4J config into the share-war/WEB-INF/classes dir. + * There is no custom classpath resolve mechanism for Share log4j, + * to log custom stuff overriding standard log4j.properties is needed. + * + * @throws MojoExecutionException + */ + protected void copyShareLog4jConfig() throws MojoExecutionException { + if (!useCustomShareLog4jConfig) { + getLog().info("NOT overriding share/WEB-INF/classes/log4j.properties"); + return; + } + + final String warOutputDir = getWarOutputDir(SHARE_WAR_PREFIX_NAME); + final String logConfDestDir = warOutputDir + "/WEB-INF/classes"; + + getLog().info("Copying Share log4j.properties to: " + logConfDestDir); + + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-resources-plugin"), + version(MAVEN_RESOURCE_PLUGIN_VERSION) + ), + goal("copy-resources"), + configuration( + element(name("outputDirectory"), logConfDestDir), + element(name("resources"), + element(name("resource"), + element(name("directory"), "src/test/resources/share"), + element(name("includes"), + element(name("include"), "log4j.properties") + ), + element(name("filtering"), "true") + ) + ) + ), + execEnv + ); + } + + /** + * Build the customized Platform webapp (i.e. the Repository, alfresco.war) + * that should be deployed by Tomcat by applying all AMPs and JARs from + * the {@code } configuration. + */ + protected void buildPlatformWar() throws MojoExecutionException { + buildCustomWarInDir(PLATFORM_WAR_PREFIX_NAME, platformModules, + alfrescoGroupId, getPlatformWarArtifactId(), alfrescoPlatformVersion); + + commentOutSecureCommsInPlatformWebXml(); + copyAlfrescoLicense(); + + String platformWarArtifactId = packageAndInstallCustomWar(PLATFORM_WAR_PREFIX_NAME); + + // Set up the custom platform war to be run by Tomcat plugin + runnerAlfrescoGroupId = "${project.groupId}"; + runnerAlfrescoPlatformWarArtifactId = platformWarArtifactId; + runnerAlfrescoPlatformVersion = "${project.version}"; + } + + /** + * Build the customized Share webapp (i.e. the share.war) + * that should be deployed by Tomcat by applying all AMPs and JARs from + * the {@code } configuration. + */ + protected void buildShareWar() throws MojoExecutionException { + buildCustomWarInDir(SHARE_WAR_PREFIX_NAME, shareModules, + alfrescoGroupId, alfrescoShareWarArtifactId, alfrescoShareVersion); + + copyShareLog4jConfig(); + + String shareWarArtifactId = packageAndInstallCustomWar(SHARE_WAR_PREFIX_NAME); + + // Set up the custom share war to be run by Tomcat plugin + runnerAlfrescoGroupId = "${project.groupId}"; + runnerAlfrescoShareWarArtifactId = shareWarArtifactId; + runnerAlfrescoShareVersion = "${project.version}"; + } + + /** + * Build the customized Activiti App webapp (i.e. the activiti-app.war) + * that should be deployed by Tomcat by applying all JARs from + * the {@code } configuration. + */ + protected void buildActivitiAppWar() throws MojoExecutionException { + buildCustomWarInDir(ACTIVITI_APP_WAR_PREFIX_NAME, activitiModules, + activitiGroupId, activitiAppWarArtifactId, activitiVersion); + + copyActivitiLog4JDevConfig(); + + String activitiAppWarArtifactId = packageAndInstallCustomWar(ACTIVITI_APP_WAR_PREFIX_NAME); + + // Set up the custom share war to be run by Tomcat plugin + runnerActivitiAppGroupId = "${project.groupId}"; + runnerActivitiAppWarArtifactId = activitiAppWarArtifactId; + runnerActivitiAppVersion = "${project.version}"; + } + + /** + * Build a customized webapp in a directory, + * applying a number of AMPs and/or JARs from alfresco maven plugin configuration. + * + * @param warName the name of the custom war + * @param modules the modules that should be applied to the custom war + * @param originalWarGroupId the Maven groupId for the original war file that should be customized + * @param originalWarArtifactId the Maven artifactId for the original war file that should be customized + * @param originalWarVersion the Maven version for the original war file that should be customized + * @throws MojoExecutionException + */ + protected void buildCustomWarInDir(String warName, + List modules, + String originalWarGroupId, + String originalWarArtifactId, + String originalWarVersion) throws MojoExecutionException { + final String warOutputDir = getWarOutputDir(warName); + final String ampsModuleDir = "modules/" + warName + "/amps"; + final String ampsOutputDir = "${project.build.directory}/" + ampsModuleDir; + List ampModules = new ArrayList<>(); + List jarModules = new ArrayList<>(); + + if (modules != null && modules.size() > 0) { + for (ModuleDependency moduleDep : modules) { + Element el = element(name("artifactItem"), + element(name("groupId"), moduleDep.getGroupId()), + element(name("artifactId"), moduleDep.getArtifactId()), + element(name("version"), moduleDep.getVersion()), + element(name("type"), moduleDep.getType()), + element(name("overWrite"), "true")); + + if (moduleDep.getArtifactId().equalsIgnoreCase("alfresco-share-services")) { + // Skip if we are not running a 5.1 version of Alfresco, 'Alfresco Share Services' + // was not used in earlier versions + if (!isPlatformVersionGtOrEqTo51()) { + continue; + } + } + + if (moduleDep.isAmp()) { + ampModules.add(el); + } else if (moduleDep.isJar()) { + jarModules.add(el); + } else { + throw new MojoExecutionException( + "Unknown module type: " + moduleDep.getType() + + " when building custom " + warName + + " war, only 'jar' and 'amp' types are allowed"); + } + } + } + + // Convert from list to array so we can add these elements below + Element[] ampModuleArray = new Element[ampModules.size()]; + ampModules.toArray(ampModuleArray); + Element[] jarModuleArray = new Element[jarModules.size()]; + jarModules.toArray(jarModuleArray); + + // Unpack the original war to /target/-war + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version(MAVEN_DEPENDENCY_PLUGIN_VERSION) + ), + goal("unpack"), + configuration( + element(name("outputDirectory"), warOutputDir), + element(name("artifactItems"), + element(name("artifactItem"), + element(name("groupId"), originalWarGroupId), + element(name("artifactId"), originalWarArtifactId), + element(name("version"), originalWarVersion), + element(name("type"), "war") + ) + ) + ), + execEnv + ); + + if (ampModuleArray.length > 0) { + // Copy AMPs to target/modules//amps so we can install them onto the WAR + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version(MAVEN_DEPENDENCY_PLUGIN_VERSION) + ), + goal("copy"), + configuration( + element(name("outputDirectory"), ampsOutputDir), + element(name("artifactItems"), ampModuleArray) + ), + execEnv + ); + + // Then apply all these amps to the unpacked war + // Call the Alfresco Maven Plugin Install Mojo directly, so we don't have to keep SDK version info here + String ampsLocation = project.getBuild().getDirectory() + "/" + ampsModuleDir; + String warLocation = project.getBuild().getDirectory() + "/" + getWarName(warName); + InstallMojo installMojo = new InstallMojo(); + installMojo.setAmpLocation(new File(ampsLocation)); + installMojo.setWarLocation(new File(warLocation)); + installMojo.setForce(true); + try { + installMojo.execute(); + } catch (MojoFailureException e) { + e.printStackTrace(); + } + } + + // Then copy all JAR dependencies to the unpacked war /target/-war/WEB-INF/lib + if (jarModuleArray.length > 0) { + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version(MAVEN_DEPENDENCY_PLUGIN_VERSION) + ), + goal("copy"), + configuration( + element(name("outputDirectory"), warOutputDir + "/WEB-INF/lib"), + element(name("artifactItems"), jarModuleArray) + ), + execEnv + ); + } + } + + /** + * Package customized war file and install it in local maven repo. + * + * @param warName the name of the custom war + * @return the customized war file artifactId, to be used by the tomcat7 plugin + * @throws MojoExecutionException + */ + protected String packageAndInstallCustomWar(String warName) throws MojoExecutionException { + final String warArtifactId = "${project.artifactId}-" + warName; + final String warSourceDir = getWarOutputDir(warName); + + // Package the customized war file + // Note. don't use the maven-war-plugin here as it will package the module files twice, once from the + // target/classes dir and once via the JAR + String warPath = project.getBuild().getDirectory() + "/" + warName + ".war"; + ZipUtil.pack(new File(warSourceDir), new File(warPath)); + + // Install the customized war file in the local maven repo + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-install-plugin"), + version(MAVEN_INSTALL_PLUGIN_VERSION) + ), + goal("install-file"), + configuration( + element(name("file"), warPath), + element(name("groupId"), "${project.groupId}"), + element(name("artifactId"), warArtifactId), + element(name("version"), "${project.version}"), + element(name("packaging"), "war") // Don't forget, otherwise installed as .POM + ) + , execEnv + ); + + return warArtifactId; + } + + /** + * Check that a database configuration has been supplied correctly + */ + protected void checkDatabaseConfig() throws MojoExecutionException { + // Only do this check if we are running alfresco.war or activiti-app.war that needs a database. + if (enablePlatform || enableActivitiApp) { + if (enableH2 && !enableMySQL && !enablePostgreSQL) { + // Run with the H2 database + return; + } else if (!enableH2 && enableMySQL && !enablePostgreSQL) { + // Run with the MySQL database + return; + } else if (!enableH2 && !enableMySQL && enablePostgreSQL) { + // Run with the PostgreSQL database + return; + } else if (!enableH2 && !enableMySQL && !enablePostgreSQL) { + // Run with a database configured via Tomcat Dependencies + return; + } else { + throw new MojoExecutionException( + "Invalid database configuration, " + + "should be enableH2 or enableMySQL or enablePostgreSQL " + + "or none (i.e. config via Tomcat Dependencies)"); + } + } + } + + /** + * Start up the embedded Tomcat server with the webapps that has been + * configured in the SDK project. + * + * @param fork true if tomcat process should be forked + * @throws MojoExecutionException + */ + protected void startTomcat(boolean fork) throws MojoExecutionException { + getLog().info("Starting Tomcat, fork = " + fork); + + List tomcatPluginDependencies = new ArrayList(); + ArrayList webapps2Deploy = new ArrayList(); + + // Add the basic Tomcat dependencies + tomcatPluginDependencies.add( + // Packaging goes faster with this lib + dependency("org.codehaus.plexus", "plexus-archiver", "2.3")); + tomcatPluginDependencies.add( + // The following dependency is needed, otherwise you get + // Caused by: java.lang.NoSuchMethodError: + // javax.servlet.ServletContext.getSessionCookieConfig()Ljavax/servlet/SessionCookieConfig + // This method is in Servlet API 3.0 + dependency("javax.servlet", "javax.servlet-api", "3.0.1")); + + // Do we have any extra Tomcat Plugin dependencies to include? + if (tomcatDependencies != null && tomcatDependencies.size() > 0) { + for (TomcatDependency tomcatDep : tomcatDependencies) { + tomcatPluginDependencies.add( + dependency(tomcatDep.getGroupId(), tomcatDep.getArtifactId(), tomcatDep.getVersion())); + } + } + + if (enableH2) { + tomcatPluginDependencies.add( + // Bring in the flat file H2 database + dependency("com.h2database", "h2", "1.4.190")); + + if (enablePlatform) { + // Copy the h2 scripts for the Alfresco Repository database + copyH2Dialect(); + } + } else if (enableMySQL) { + tomcatPluginDependencies.add( + // Bring in the MySQL JDBC Driver + dependency("mysql", "mysql-connector-java", "5.1.32")); + } else if (enablePostgreSQL) { + tomcatPluginDependencies.add( + // Bring in the PostgreSQL JDBC Driver + dependency("org.postgresql", "postgresql", "9.4-1201-jdbc41")); + } + + if (enablePlatform) { + webapps2Deploy.add(createWebAppElement( + runnerAlfrescoGroupId, runnerAlfrescoPlatformWarArtifactId, runnerAlfrescoPlatformVersion, + "/alfresco", null)); + } + + if (enableShare) { + webapps2Deploy.add(createWebAppElement( + runnerAlfrescoGroupId, runnerAlfrescoShareWarArtifactId, runnerAlfrescoShareVersion, + shareContextPath, null)); + } + + if (enableSolr) { + webapps2Deploy.add(getSolrWebappElement()); + } + + if (enableApiExplorer) { + webapps2Deploy.add(createWebAppElement( + alfrescoGroupId, alfrescoApiExplorerArtifactId, alfrescoApiExplorerVersion, + "/api-explorer", null)); + } + + if (enableActivitiApp) { + webapps2Deploy.add(createWebAppElement( + runnerActivitiAppGroupId, runnerActivitiAppWarArtifactId, runnerActivitiAppVersion, + "/activiti-app", null)); + } + + if (enableActivitiAdmin) { + webapps2Deploy.add(createWebAppElement( + activitiGroupId, activitiAdminWarArtifactId, activitiVersion, "/activiti-admin", null)); + } + + if (tomcatCustomWebapps != null && !tomcatCustomWebapps.isEmpty()) { + // We got extra custom webapps to deploy + for (TomcatWebapp customWebapp: tomcatCustomWebapps) { + webapps2Deploy.add(createWebAppElement( + customWebapp.getGroupId(), customWebapp.getArtifactId(), customWebapp.getVersion(), + customWebapp.getContextPath(), customWebapp.getContextFile())); + } + } + + // This might be ugly, the MojoExecuter will only accept Element[] and we need this list to be dynamic + // to avoid NPEs. If there's a better way to do this, then feel free to change it! + Element[] webapps = new Element[webapps2Deploy.size()]; + webapps2Deploy.toArray(webapps); + + // Set up the system properties that should be set for Tomcat + ArrayList systemProps = new ArrayList(); + systemProps.add(element(name("java.io.tmpdir"), "${project.build.directory}")); + if (enableSolr) { + systemProps.add(element(name("solr.solr.home"), solrHome)); + } + if (enableActivitiApp) { + // Should be in activiti-jar/src/test/resources + systemProps.add(element(name("log4j.configuration"), "log4j-dev.properties")); + } + // Add custom system properties defined in plugin config + if (tomcatSystemProperties != null && !tomcatSystemProperties.isEmpty()) { + for (Map.Entry sysProp : tomcatSystemProperties.entrySet()) { + systemProps.add(element(name(sysProp.getKey()), sysProp.getValue())); + } + } + // This might be ugly, the MojoExecuter will only accept Element[] and we need this list to be dynamic + // to avoid NPEs. If there's a better way to do this, then feel free to change it! + Element[] systemPropArray = new Element[systemProps.size()]; + systemProps.toArray(systemPropArray); + + executeMojo( + plugin( + groupId("org.apache.tomcat.maven"), + artifactId("tomcat7-maven-plugin"), + version(MAVEN_TOMCAT7_PLUGIN_VERSION), + tomcatPluginDependencies + ), + goal("run"), + configuration( + element(name("fork"), fork ? "true" : "false"), + + /* + * SDK Projects doesn't have packaging set to 'war', they are JARs or POMs, + * this setting ignores that fact. + */ + element(name("ignorePackaging"), "true"), + + /* + * Make sure Catalina classes are picked up when we got virtual webapp contexts with classpaths. + * + * If true a new classLoader separated from maven core will be created to start. + * This does not work to run with, getting : + * NoSuchMethodError: javax.servlet.ServletContext.getSessionCookieConfig + * (which lives in Servlet API 3) + * + */ + element(name("useSeparateTomcatClassLoader"), "true"), + + /* + * Bring in stuff in the test classpath, such as the alfresco-global.properties + * that should be used + */ + element(name("useTestClasspath"), "true"), + + /** + * Set up where Solr Home directory is + */ + element(name("systemProperties"), systemPropArray), + + /* Should this class loader delegate to the parent class loader before searching its + own repositories (i.e. the usual Java2 delegation model). + Prevent parent classloader delegation, each webapp loads. + If set to true then you will get a truckload of Solr logging as + the alf_data_dev/solr4/config/log4j-solr.properties file is not picked up. + This also fixes issues with the Google Guava Library, which this tomcat plugin uses + version 10.0.1 of but Solr uses 14.0.1 */ + element(name("delegate"), "false"), + + /* + * Encode url in UTF-8 for proper character handling --> + */ + element(name("uriEncoding"), "UTF-8"), + + /* + * Bring in the webapps that should be deployed and run + */ + element(name("webapps"), webapps) + + ), + execEnv + ); + } + + /** + * Create a webapp element that can be added as a webapp configuration to the Tomcat plug-in. + *

+ * For example: + *

+     *    {@code
+     *    
+     *        ${project.groupId}
+     *        share
+     *        ${project.version}
+     *        war
+     *        true
+     *        /share
+     *        ${project.build.directory}/contexts/context-share.xml
+     *    
+     *    }
+     * 
+ * + * @param groupId + * @param artifactId + * @param version + * @param contextPath + * @param contextFile + * @return + */ + private Element createWebAppElement(String groupId, + String artifactId, + String version, + String contextPath, + String contextFile) { + String errorStr = "cannot be null when creating webapp element for Tomcat 7 plugin"; + if (StringUtils.isBlank(groupId)) { + getLog().error("Maven Group Id " + errorStr); + } + if (StringUtils.isBlank(artifactId)) { + getLog().error("Maven Artifact Id " + errorStr); + } + if (StringUtils.isBlank(version)) { + getLog().error("Maven Version number " + errorStr); + } + + Element groupIdEl = element(name("groupId"), groupId); + Element artifactIdEl = element(name("artifactId"), artifactId); + Element versionEl = element(name("version"), version); + Element typeEl = element(name("type"), "war"); + // Make sure webapp is loaded with context and everything, + // if set to 'false' then you will get 404 when trying to access the webapp from browser + Element asWebappEl = element(name("asWebapp"), "true"); + Element contextPathEl = element(name("contextPath"), contextPath); + + Element e; + if (StringUtils.isNotBlank(contextFile)) { + e = element(name("webapp"), + groupIdEl, artifactIdEl, versionEl, typeEl, asWebappEl, contextPathEl, + element(name("contextFile"), contextFile)); + + } else { + e = element(name("webapp"), + groupIdEl, artifactIdEl, versionEl, typeEl, asWebappEl, contextPathEl); + } + + getLog().info(e.toDom().toUnescapedString()); + + return e; + } + + /** + * Returns true if current platform version (i.e. version of alfresco.war) is + * >= 5.1 + * + * @return true if platform version >= 5.1 + */ + private boolean isPlatformVersionGtOrEqTo51() { + if (getPlatformVersionNumber() >= 51) { + return true; + } + + return false; + } + + /** + * Returns true if current platform version (i.e. version of alfresco.war) is + * <= 4.2 + * + * @return true if platform version <= 4.2 + */ + private boolean isPlatformVersionLtOrEqTo42() { + if (getPlatformVersionNumber() <= 42) { + return true; + } + + return false; + } + + /** + * Grabs the first 2 numbers in the version string + * + * @return major and minor version as int, such as 41,50,51 + */ + private int getPlatformVersionNumber() { + return Integer.parseInt(alfrescoPlatformVersion.replaceAll("[^0-9]", "").substring(0, 2)); + } + + /** + * Get the Solr artifactId, it changes when we move to Solr 4 in Alfresco version 5 + * + * @return the Maven artifactId for Solr + */ + private String getSolrArtifactId() { + // artifactId for Solr defaults to version 4 = alfresco-solr4 + + if (isPlatformVersionLtOrEqTo42()) { + // Solr version 1 is used in Alfresco 4.0 -> 4.2, Solr version 4.0 was introduced in Alfresco version 5.0 + alfrescoSolrArtifactId = "alfresco-solr"; + } + + return alfrescoSolrArtifactId; + } + + /** + * Get the Alfresco Platform Webapp artifactId (i.e. for alfresco.war), + * it changes from 'alfresco' to 'alfresco-platform' in 5.1. + * + * @return the Maven artifactId for Alfresco Platform webapp + */ + private String getPlatformWarArtifactId() { + // Default alfrescoPlatformWarArtifactId is 'alfresco-platform' + + if (isPlatformVersionGtOrEqTo51() == false) { + // We are running version 4.2 or 5.0, so use older artifactId + alfrescoPlatformWarArtifactId = "alfresco"; + } else if (alfrescoEdition.equals(ALFRESCO_ENTERPRISE_EDITION)) { + alfrescoPlatformWarArtifactId = "alfresco-enterprise"; + } + + return alfrescoPlatformWarArtifactId; + } + + /** + * Get the Solr webapp element for use by Tomcat, it changes when we move to Solr 4 in Alfresco version 5 + * + * @return tomcat webapp element + */ + private Element getSolrWebappElement() { + Element webappElement = null; + + if (isPlatformVersionLtOrEqTo42()) { + // Solr version 1.0 + webappElement = createWebAppElement("${project.groupId}", getSolrArtifactId(), "${project.version}", + "/solr", "${project.build.testOutputDirectory}/tomcat/context-solr.xml"); + } else { + // Solr version 4.0 + webappElement = createWebAppElement(alfrescoGroupId, getSolrArtifactId(), alfrescoPlatformVersion, + "/solr4", "${project.build.testOutputDirectory}/tomcat/context-solr.xml"); + } + + return webappElement; + } + + /** + * TODO: From 5.1.e and onwards we have the alfresco-repository:h2scripts:jar artifact, so we potentially only need to do this for older than 5.1.e + * + * + * Extract PostgreSQL dialect and ibatis from alfresco-repository, rename to H2Dialect in the test-classes + * + * @return + */ + private void copyH2Dialect() throws MojoExecutionException { + getLog().info("Unpacking DB Dialects and ibatis files from alfresco-repository artifact"); + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version(MAVEN_DEPENDENCY_PLUGIN_VERSION) + ), + goal("unpack"), + configuration( + element(name("outputDirectory"), "${project.build.testOutputDirectory}"), + element(name("artifactItems"), + element(name("artifactItem"), + element(name("groupId"), alfrescoGroupId), + element(name("artifactId"), "alfresco-repository"), + element(name("version"), alfrescoPlatformVersion), + element(name("includes"), "alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/dbscripts/upgrade/*/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/*") + ) + ) + ), + execEnv + ); + + // If we're in enterprise we need to make sure we grab everything + if (this.alfrescoEdition.equals(ALFRESCO_ENTERPRISE_EDITION)) { + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version(MAVEN_DEPENDENCY_PLUGIN_VERSION) + ), + goal("unpack"), + configuration( + element(name("outputDirectory"), "${project.build.testOutputDirectory}"), + element(name("artifactItems"), + element(name("artifactItem"), + element(name("groupId"), alfrescoGroupId), + element(name("artifactId"), "alfresco-enterprise-repository"), + element(name("version"), alfrescoPlatformVersion), + element(name("includes"), "alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/dbscripts/upgrade/*/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/*") + ) + ) + ), + execEnv + ); + } + + getLog().info("Copying H2 Dialect SQL create files into target/test-classes"); + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-resources-plugin"), + version(MAVEN_RESOURCE_PLUGIN_VERSION) + ), + goal("copy-resources"), + configuration( + element(name("outputDirectory"), "${project.build.testOutputDirectory}"), + element(name("resources"), + element(name("resource"), + element(name("directory"), "${project.build.testOutputDirectory}/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect"), + element(name("includes"), + element(name("include"), "*") + ), + element(name("targetPath"), "alfresco/dbscripts/create/org.hibernate.dialect.H2Dialect") + ), + element(name("resource"), + element(name("directory"), "${project.build.testOutputDirectory}/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect"), + element(name("includes"), + element(name("include"), "*") + ), + element(name("targetPath"), "alfresco/ibatis/org.hibernate.dialect.H2Dialect") + ) + ) + ), + execEnv + ); + + } + + + /** + * The directory where the custom war will be assembled + * + * @param baseWarName a war base name, such as 'platform' or 'share' + * @return a directory such as: .../aio/target/platform-war + */ + private String getWarOutputDir(String baseWarName) { + return project.getBuild().getDirectory() + "/" + getWarName(baseWarName); + } + + /** + * Get the war filename based on passed in war type + * + * @param baseWarName a war base name, such as 'platform' or 'share' + * @return + */ + private String getWarName(String baseWarName) { + return baseWarName + "-war"; + } +} diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/InstallMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/InstallMojo.java index 8147b902..ceb86754 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/InstallMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/InstallMojo.java @@ -1,3 +1,20 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.alfresco.maven.plugin; import java.io.File; diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/IntegrationTestMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/IntegrationTestMojo.java new file mode 100644 index 00000000..4485c075 --- /dev/null +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/IntegrationTestMojo.java @@ -0,0 +1,274 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK project. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.alfresco.maven.plugin; + +import org.alfresco.maven.plugin.config.ModuleDependency; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Plugin; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.zeroturnaround.zip.ZipUtil; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static org.twdata.maven.mojoexecutor.MojoExecutor.*; + +/** + * Alfresco Plugin mojo that are used when you want to run Integration Tests. + * It will package up all the Integration Test classes and execute contained + * tests with the Maven Failsafe plugin. The test classes will be added + * to the platform war so they can be executed remotely via + * the ${@link org.alfresco.rad.test.AlfrescoTestRunner} + *

+ * The Alfresco RAD module is also added to the Platform WAR so + * the Alfresco Test runner classes are available. + * + * @author martin.bergljung@alfresco.com + * @since 3.0 + */ +@Mojo(name = "it", + defaultPhase = LifecyclePhase.INTEGRATION_TEST, + aggregator = true, // Only run against the top-level project in a Maven build + requiresDependencyResolution = ResolutionScope.TEST) +public class IntegrationTestMojo extends AbstractRunMojo { + + @Override + public void execute() throws MojoExecutionException { + execEnv = executionEnvironment( + project, + session, + pluginManager + ); + + if (enableSolr) { + unpackSolrConfig(); + fixSolrHomePath(); + replaceSolrConfigProperties(); + installSolr10InLocalRepo(); + } + + if (enableTestProperties && enablePlatform) { + copyAlfrescoGlobalProperties(); + renameAlfrescoGlobalProperties(); + } + + String testJarArtifactId = null; + if (enablePlatform) { + // Add alfresco-rad module to platform WAR + // So we got access to Alfresco Test Runner in the server + platformModules.add( + new ModuleDependency( + "org.alfresco.maven", + "alfresco-rad", + "${alfresco.sdk.version}", + ModuleDependency.TYPE_JAR)); + + // Create a JAR with all tests and add to module dependencies for platform WAR + // So we can run tests on the server + copyTestClassesFromSubModules2Parent(); + testJarArtifactId = packageAndInstallTestsJar(); + platformModules.add( + new ModuleDependency( + project.getGroupId(), + testJarArtifactId, + project.getVersion(), + ModuleDependency.TYPE_JAR)); + // Now build the platform WAR + buildPlatformWar(); + } + + if (enableShare) { + buildShareWar(); + } + + if (enableActivitiApp) { + buildActivitiAppWar(); + } + + if (startTomcat) { + boolean fork = true; + startTomcat(fork); + runIntegrationTests(testJarArtifactId); + stopTomcat(); + } + } + + /** + * In an AIO project copy all integration test (IT) test-classes from sub projects/modules + * to the parent target/test-classes + * + * @throws MojoExecutionException + */ + protected void copyTestClassesFromSubModules2Parent() throws MojoExecutionException { + // Get sub-module names, so we can see where to copy test classes from + List childModules = project.getModules(); + if (childModules == null || childModules.size() <= 0) { + // Running in a single JAR module, nothing to copy, + // all test classes are already in top level target/test-classes + return; + } + + for (String module : childModules) { + getLog().info("Copying integration test-classes (*IT.class) from module '" + module + + "' to parent target/test-classes"); + + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-resources-plugin"), + version(MAVEN_RESOURCE_PLUGIN_VERSION) + ), + goal("copy-resources"), + configuration( + element(name("outputDirectory"), "${project.build.testOutputDirectory}"), + element(name("resources"), + element(name("resource"), + element(name("directory"), module + "/target/test-classes"), + element(name("includes"), + element(name("include"), "**/*.class") + ), + element(name("filtering"), "false") + ) + ) + ), + execEnv + ); + } + } + + /** + * Package all IT Tests in JAR file and install it in local maven repo. + * + * @return the customized JAR file artifactId, to be used by the failsafe plugin + * @throws MojoExecutionException + */ + protected String packageAndInstallTestsJar() throws MojoExecutionException { + final String jarArtifactId = project.getArtifactId() + "-IT-classes"; + + // Package the JAR file with all the Integration Tests (IT) + // Note. don't use the maven-war-plugin here as it will package the module files twice, once from the + // target/classes dir and once via the JAR + final String jarPath = project.getBuild().getDirectory() + "/" + jarArtifactId + ".jar"; + final String jarSourceDir = project.getBuild().getDirectory() + "/test-classes"; + + ZipUtil.pack(new File(jarSourceDir), new File(jarPath)); + + getLog().info("Installing integration test JAR into local Maven repo."); + + // Install the Test JAR file in the local maven repo + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-install-plugin"), + version(MAVEN_INSTALL_PLUGIN_VERSION) + ), + goal("install-file"), + configuration( + element(name("file"), jarPath), + element(name("groupId"), "${project.groupId}"), + element(name("artifactId"), jarArtifactId), + element(name("version"), "${project.version}"), + element(name("packaging"), "jar") // Don't forget, otherwise installed as .POM + ) + , execEnv + ); + + return jarArtifactId; + } + + /** + * Run all IT tests contained in JAR with passed in artifact ID. Group ID and Version will be the same + * as the project. + * + * @param testJarArtifactId + * @throws MojoExecutionException + */ + protected void runIntegrationTests(String testJarArtifactId) throws MojoExecutionException { + getLog().info("Executing integration tests (*IT.class)..."); + + // JUnit runner + List failsafePluginDependencies = new ArrayList(); + failsafePluginDependencies.add(dependency("org.apache.maven.surefire", "surefire-junit47", "2.19.1")); + + // Add dependencies to classes under test + List classpathElements = new ArrayList<>(); + List childModules = project.getModules(); + if (childModules != null && childModules.size() > 0) { + // Get sub-module names, so we can see what libs to include + for (String module : childModules) { + String classpathElement = project.getBasedir() + "/" + module + "/target/" + module + "-1.0-SNAPSHOT.jar"; + getLog().info("Adding module '" + classpathElement + "' to test classpath"); + classpathElements.add(element(name("additionalClasspathElement"), classpathElement)); + } + } + + // Execute Failsafe Mojo + Plugin failsafePlugin = plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-failsafe-plugin"), + version("2.19.1"), + failsafePluginDependencies + ); + getLog().info("Start executing failsafe Mojo..."); + + // This might be ugly, the MojoExecuter will only accept Element[] and we need this list to be dynamic + // to avoid NPEs. If there's a better way to do this, then feel free to change it! + Element[] classpathElementArray = new Element[classpathElements.size()]; + classpathElements.toArray(classpathElementArray); + + executeMojo(failsafePlugin, + goal("integration-test"), + configuration( + element(name("includes"), + element(name("include"), "**/*IT.class") + ), + element(name("additionalClasspathElements"), + classpathElementArray + ), + // IT Test dependency to scan + element(name("dependenciesToScan"), + element(name("dependency"), project.getGroupId() + ":" + testJarArtifactId) + ) + ), + execEnv + ); + + getLog().info("Stopped executing failsafe Mojo"); + } + + protected void stopTomcat() throws MojoExecutionException { + getLog().info("Stopping Tomcat..."); + + Plugin tomcatPlugin = plugin( + groupId("org.apache.tomcat.maven"), + artifactId("tomcat7-maven-plugin"), + version(MAVEN_TOMCAT7_PLUGIN_VERSION) + ); + + executeMojo(tomcatPlugin, + goal("shutdown") , + configuration(), + execEnv + ); + } +} \ No newline at end of file diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshMojo.java index d6db4710..26427eb0 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshMojo.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Alfresco Software Limited. + * Copyright (C) 2017 Alfresco Software Limited. *

* This file is part of the Alfresco SDK. *

diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshRepoWebappMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshRepoWebappMojo.java index 9dab8c03..c741c90a 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshRepoWebappMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshRepoWebappMojo.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Alfresco Software Limited. + * Copyright (C) 2017 Alfresco Software Limited. *

* This file is part of the Alfresco SDK. *

diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshShareWebappMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshShareWebappMojo.java index 3bc9a23a..157e1898 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshShareWebappMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RefreshShareWebappMojo.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Alfresco Software Limited. + * Copyright (C) 2017 Alfresco Software Limited. *

* This file is part of the Alfresco SDK. *

diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RunMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RunMojo.java index 7644b05f..62973acd 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RunMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/RunMojo.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2016 Alfresco Software Limited. + * Copyright (C) 2017 Alfresco Software Limited. *

* This file is part of the Alfresco SDK. *

@@ -17,35 +17,19 @@ */ package org.alfresco.maven.plugin; -import org.alfresco.maven.plugin.config.ModuleDependency; -import org.alfresco.maven.plugin.config.TomcatDependency; -import org.alfresco.maven.plugin.config.TomcatWebapp; -import org.apache.commons.lang.StringUtils; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.model.Dependency; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.BuildPluginManager; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.FileUtils; -import org.zeroturnaround.zip.ZipUtil; - -import java.io.*; -import java.util.*; import static org.twdata.maven.mojoexecutor.MojoExecutor.*; /** - * Runner component that can be used to test your extension. + * Alfresco Plugin mojo that are used when you want to run the Alfresco server with all the webapps. + * The server blocks after startup. * - * @author ole.hejlskov, martin.bergljung + * @author martin.bergljung * @version 1.0 * @since 3.0.0 */ @@ -53,283 +37,7 @@ import static org.twdata.maven.mojoexecutor.MojoExecutor.*; defaultPhase = LifecyclePhase.TEST, aggregator = true, // Only run against the top-level project in a Maven build requiresDependencyResolution = ResolutionScope.TEST) -public class RunMojo extends AbstractMojo { - public static final String MAVEN_DEPENDENCY_PLUGIN_VERSION = "2.10"; - public static final String MAVEN_INSTALL_PLUGIN_VERSION = "2.5.2"; - public static final String MAVEN_REPLACER_PLUGIN_VERSION = "1.5.3"; - public static final String MAVEN_RESOURCE_PLUGIN_VERSION = "2.7"; - public static final String MAVEN_TOMCAT7_PLUGIN_VERSION = "2.2"; - public static final String MAVEN_BUILD_HELPER_PLUGIN_VERSION = "1.12"; - - public static final String PLATFORM_WAR_PREFIX_NAME = "platform"; - public static final String SHARE_WAR_PREFIX_NAME = "share"; - public static final String ACTIVITI_APP_WAR_PREFIX_NAME = "activitiApp"; - - public static final String ALFRESCO_ENTERPRISE_EDITION = "enterprise"; - public static final String ALFRESCO_COMMUNITY_EDITION = "community"; - - @Component - protected MavenProject project; - - @Component - protected MavenSession session; - - @Component - private BuildPluginManager pluginManager; - - /** - * The following properties that start with 'maven.' are used to control the - * Alfresco Maven plugin itself. - *

-     * For example:
-     *    {@code
-     *      
-     *          org.alfresco.maven.plugin
-     *          alfresco-maven-plugin
-     *          3.0.0
-     *          
-     *              community
-     *              true
-     *              true
-     *              true
-     *              false*
-     *              
-     *                  
-     *                      ${alfresco.groupId}
-     *                      alfresco-share-services
-     *                      ${alfresco.share.version}
-     *                      amp
-     *                  
-     *              
-     *          
-     *      
-     *    }
-     * 
- */ - - /** - * Switch to enable/disable the Apache Solr 4 web application when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enableSolr", defaultValue = "true") - protected boolean enableSolr; - - /** - * Switch to enable/disable the H2 database when running embedded Tomcat. - * This also brings in the needed H2 database scripts. - */ - @Parameter(property = "maven.alfresco.enableH2", defaultValue = "false") - protected boolean enableH2; - - /** - * Switch to enable/disable the MySQL database when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enableMySQL", defaultValue = "false") - protected boolean enableMySQL; - - /** - * Switch to enable/disable the PostgreSQL database when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enablePostgreSQL", defaultValue = "false") - protected boolean enablePostgreSQL; - - /** - * Switch to enable/disable the Enterprise database (such as Oracle or MS SQL Server) when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enableEnterpriseDb", defaultValue = "false") - protected boolean enableEnterpriseDb; - - /** - * Switch to enable/disable the Platform/Repository (alfresco.war) when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enablePlatform", defaultValue = "true") - protected boolean enablePlatform; - - /** - * Switch to enable/disable the Share (share.war) when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enableShare", defaultValue = "true") - protected boolean enableShare; - - /** - * Enables the use of custom context path for the Share webapp. - * Some solution integrators uses a custom context path for Share in their projects. - * This property enables them to continue to do that in SDK 3 without having to completely override the - * Maven Tomcat plugin configuration, or not use it at all and go back the good old runner project again... - */ - @Parameter(property = "maven.alfresco.shareContextPath", defaultValue = "/share") - protected String shareContextPath; - - /** - * Share Log4j.properties configuration cannot be customized via extension - * put on the classpath, like on the platform side. - * So we need to override the log4j.properties in share/WEB-INF/classes - * to be able to log from custom code. - * This property can be used to turn off this overriding, to produce a WAR with - * the standard Share log4j.properties file. - */ - @Parameter(property = "maven.alfresco.useCustomShareLog4jConfig", defaultValue = "true") - protected boolean useCustomShareLog4jConfig; - - /** - * Switch to enable/disable the Alfresco REST API Explorer (api-explorer.war) when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enableApiExplorer", defaultValue = "false") - protected boolean enableApiExplorer; - - /** - * Switch to enable/disable Alfresco Activiti Workflow Engine (activiti-app.war) when running embedded Tomcat. - * This contains the Alfresco Activiti webapp, including the workflow engine. - * This webapp is also the user interface for people involved in the task and processes - * running in the Activiti engine. - * You also use this webapp to create and manage process definitions, and to display and define analytics - * reports on users' tasks and processes. - */ - @Parameter(property = "maven.alfresco.enableActivitiApp", defaultValue = "false") - protected boolean enableActivitiApp; - - /** - * Switch to enable/disable Alfresco Activiti Admin (activiti-admin.war) when running embedded Tomcat. - * This contains the Alfresco Activiti Administrator webapp. You use this to administer and monitor your - * Alfresco Activiti engines. - * - */ - @Parameter(property = "maven.alfresco.enableActivitiAdmin", defaultValue = "false") - protected boolean enableActivitiAdmin; - - /** - * Switch to enable/disable test properties when running embedded Tomcat. - */ - @Parameter(property = "maven.alfresco.enableTestProperties", defaultValue = "true") - protected boolean enableTestProperties; - - /** - * Control if Tomcat 7 Plugin should be kicked off and start Apache Tomcat - */ - @Parameter(property = "maven.alfresco.startTomcat", defaultValue = "true") - protected boolean startTomcat; - - /** - * Directory containing test files that should be used when running embedded Tomcat - */ - @Parameter(property = "maven.alfresco.testFolder", defaultValue = "src/test/properties/${env}") - protected String testFolder; - - /** - * Test files in testFolder that should be included when running embedded Tomcat - */ - @Parameter(property = "maven.alfresco.testInclude", defaultValue = "**") - protected String testInclude; - - /** - * JARs and AMPs that should be overlayed/applied to the Platform/Repository WAR (i.e. alfresco.war) - */ - @Parameter(property = "maven.alfresco.platform.modules", defaultValue = "") - protected List platformModules; - - /** - * JARs and AMPs that should be overlayed/applied to the Share WAR (i.e. share.war) - */ - @Parameter(property = "maven.alfresco.share.modules", defaultValue = "") - protected List shareModules; - - /** - * JARs that should be overlayed/applied to the Activiti App WAR (i.e. activiti-app.war) - */ - @Parameter(property = "maven.activiti.modules", defaultValue = "") - protected List activitiModules; - - /** - * Community Edition or Enterprise Edition? (i.e community or enterprise) - */ - @Parameter(property = "maven.alfresco.edition", defaultValue = ALFRESCO_COMMUNITY_EDITION) - protected String alfrescoEdition; - - /** - * Tomcat Dependencies that should be added to the Embedded Tomcat configuration before start. - * Normally there would not be any extra dependencies, but could be if you run an Enterprise database - * such as Oracle, for which there's no quick config, such as enableH2, enableMySQL, or enablePostgreSQL. - */ - @Parameter(property = "maven.alfresco.tomcat.dependencies", defaultValue = "") - protected List tomcatDependencies; - - /** - * System Properties to feed the Tomcat plugin before start. - * Normally there would not be any extra dependencies, but we could run a custom webapp that needed - * a custom sys prop set. - */ - @Parameter(property = "maven.alfresco.tomcat.system.properties", defaultValue = "") - protected Map tomcatSystemProperties; - - /** - * Custom webapps that should be deployed to the embedded Tomcat engine. - * Normally there would not be any extra webapps, but we could run a bigger project that uses - * some custom webapp. - */ - @Parameter(property = "maven.alfresco.tomcat.custom.webapps", defaultValue = "") - protected List tomcatCustomWebapps; - - /** - * Maven GAV properties for standard Alfresco web applications. - */ - @Parameter(property = "alfresco.groupId", defaultValue = "org.alfresco") - protected String alfrescoGroupId; - - @Parameter(property = "activiti.groupId", defaultValue = "com.activiti") - protected String activitiGroupId; - - @Parameter(property = "alfresco.platform.war.artifactId", defaultValue = "alfresco-platform") - protected String alfrescoPlatformWarArtifactId; - - @Parameter(property = "alfresco.share.war.artifactId", defaultValue = "share") - protected String alfrescoShareWarArtifactId; - - @Parameter(property = "alfresco.solr.artifactId", defaultValue = "alfresco-solr4") - protected String alfrescoSolrArtifactId; - - @Parameter(property = "alfresco.api.explorer.artifactId", defaultValue = "api-explorer") - protected String alfrescoApiExplorerArtifactId; - - @Parameter(property = "activiti.app.war.artifactId", defaultValue = "activiti-app") - protected String activitiAppWarArtifactId; - - @Parameter(property = "activiti.admin.war.artifactId", defaultValue = "activiti-admin") - protected String activitiAdminWarArtifactId; - - @Parameter(property = "alfresco.platform.version", defaultValue = "5.2.e") - protected String alfrescoPlatformVersion; - - @Parameter(property = "alfresco.share.version", defaultValue = "5.2.d") - protected String alfrescoShareVersion; - - @Parameter(property = "alfresco.api.explorer.version", defaultValue = "5.2.e") - protected String alfrescoApiExplorerVersion; - - @Parameter(property = "activiti.version", defaultValue = "1.5.3") - protected String activitiVersion; - - /** - * Directory that contains the Alfresco Solr 4 configuration - */ - @Parameter(property = "solr.home", defaultValue = "${project.basedir}/${alfresco.data.location}/solr") - protected String solrHome; - - /** - * Maven GAV properties for customized alfresco.war, share.war, activiti-app.war - * Used by the Maven Tomcat 7 Plugin - */ - private String runnerAlfrescoGroupId; - private String runnerAlfrescoPlatformWarArtifactId; - private String runnerAlfrescoShareWarArtifactId; - private String runnerAlfrescoPlatformVersion; - private String runnerAlfrescoShareVersion; - private String runnerActivitiAppGroupId; - private String runnerActivitiAppWarArtifactId; - private String runnerActivitiAppVersion; - - /** - * The Maven environment that this mojo is executed in - */ - private ExecutionEnvironment execEnv; +public class RunMojo extends AbstractRunMojo { public void execute() throws MojoExecutionException { execEnv = executionEnvironment( @@ -364,1067 +72,8 @@ public class RunMojo extends AbstractMojo { if (startTomcat) { checkDatabaseConfig(); - startTomcat(); + boolean fork = false; + startTomcat(fork); } } - - /** - * Download and unpack the Solr 4 configuration as we don't have it in the project. - * It will reside under /alf_data_dev/solr - * - * @throws MojoExecutionException - */ - protected void unpackSolrConfig() throws MojoExecutionException { - getLog().info("Unpacking Solr config"); - - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-dependency-plugin"), - version(MAVEN_DEPENDENCY_PLUGIN_VERSION) - ), - goal("unpack"), - configuration( - element(name("outputDirectory"), solrHome), - element(name("artifactItems"), - element(name("artifactItem"), - element(name("groupId"), alfrescoGroupId), - element(name("artifactId"), getSolrArtifactId()), - element(name("version"), alfrescoPlatformVersion), - // The Solr config is not in a special file with classifier config if <= 4.2 - isPlatformVersionLtOrEqTo42() ? element(name("classifier"), "") : element(name("classifier"), "config"), - element(name("type"), "zip") - ) - ) - ), - execEnv - ); - } - - /** - * For windows paths, convert single \ to / for the ${alfresco.solr.data.dir} path, - * by default it will be c:\bla\, we need forward slash or double backslash. - * - * @throws MojoExecutionException - */ - protected void fixSolrHomePath() throws MojoExecutionException { - getLog().info("Fix Solr Home Path to work in Windows"); - - executeMojo( - plugin( - groupId("org.codehaus.mojo"), - artifactId("build-helper-maven-plugin"), - version(MAVEN_BUILD_HELPER_PLUGIN_VERSION) - ), - goal("regex-property"), - configuration( - element(name("name"), "solrDataDir"), - element(name("value"), solrHome), - element(name("regex"), "\\\\"), - element(name("replacement"), "/"), - element(name("failIfNoMatch"), "false") - ), - execEnv - ); - } - - /** - * Replace property placeholders in configuration files for the cores, so the - * index files can be found for each core when Solr starts up. - * - * @throws MojoExecutionException - */ - protected void replaceSolrConfigProperties() throws MojoExecutionException { - getLog().info("Replacing Solr config properties"); - executeMojo( - plugin( - groupId("com.google.code.maven-replacer-plugin"), - artifactId("replacer"), - version(MAVEN_REPLACER_PLUGIN_VERSION) - ), - goal("replace"), - configuration( - element(name("regex"), "false"), - element(name("includes"), - element(name("include"), solrHome + "/archive-SpacesStore/conf/solrcore.properties"), - element(name("include"), solrHome + "/workspace-SpacesStore/conf/solrcore.properties") - ), - element(name("replacements"), - element(name("replacement"), - element(name("token"), "@@ALFRESCO_SOLR4_DATA_DIR@@"), - element(name("value"), "${solrDataDir}/index") - ) - ) - ), - execEnv - ); - } - - /** - * If we are in Alfresco version 4.2 or younger the Solr 1.0 WAR is not available as Maven artifact, just - * as part of a ZIP file, so install it locally so we can deploy from embedded tomcat - * - * @throws MojoExecutionException - */ - protected void installSolr10InLocalRepo() throws MojoExecutionException { - if (isPlatformVersionLtOrEqTo42()) { - getLog().info("Installing Solr 1.0 WAR in local Maven repo"); - - // Install the Solr 1.0 war file in local maven repo - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-install-plugin"), - version(MAVEN_INSTALL_PLUGIN_VERSION) - ), - goal("install-file"), - configuration( - element(name("file"), solrHome + "/apache-solr-1.4.1.war"), - element(name("groupId"), "${project.groupId}"), - element(name("artifactId"), getSolrArtifactId()), - element(name("version"), "${project.version}"), - element(name("packaging"), "war") - ) - , execEnv - ); - } - } - - /** - * Replaces web.xml where applicable in platform webapp (alfresco.war), - * commenting out the security-constraints. - *

- * This is only needed for 4.2, 5.0 (5.1 handles it automatically when turning off ssl via props) - * - * @throws MojoExecutionException - */ - protected void commentOutSecureCommsInPlatformWebXml() throws MojoExecutionException { - if (isPlatformVersionGtOrEqTo51()) { - return; - } - - String webInfPath = getWarOutputDir(PLATFORM_WAR_PREFIX_NAME) + "/WEB-INF/"; - String webXmlFilePath = webInfPath + "web.xml"; - - getLog().info("Commenting out the security-constraints in " + webXmlFilePath); - - executeMojo( - plugin( - groupId("com.google.code.maven-replacer-plugin"), - artifactId("replacer"), - version(MAVEN_REPLACER_PLUGIN_VERSION) - ), - goal("replace"), - configuration( - element(name("ignoreErrors"), "true"), - element(name("file"), webXmlFilePath), - element(name("outputDir"), webInfPath), - element(name("preserveDir"), "false"), - element(name("replacements"), - element(name("replacement"), - element(name("token"), ""), - element(name("value"), ""), - element(name("value"), " -->") - ) - ) - ), - execEnv - ); - } - - /** - * Copy the different alfresco-global-*.properties files (there are one for each open source db and one for - * enterprise db config) that will be used when running Alfresco. It contains database connection parameters and - * other general configuration for Alfresco Repository (alfresco.war) - * - * @throws MojoExecutionException - */ - protected void copyAlfrescoGlobalProperties() throws MojoExecutionException { - getLog().info("Copying and filtering alfresco-global-*.properties files to target/test-classes"); - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-resources-plugin"), - version(MAVEN_RESOURCE_PLUGIN_VERSION) - ), - goal("copy-resources"), - configuration( - element(name("outputDirectory"), "${project.build.testOutputDirectory}"), - element(name("resources"), - element(name("resource"), - element(name("directory"), testFolder), - element(name("includes"), - element(name("include"), testInclude) - ), - element(name("filtering"), "true") - ) - ) - ), - execEnv - ); - } - - /** - * Rename the configured database specific alfresco-global-*.properties file to - * alfresco-global.properties so it will be used during Tomcat run. - * - * @throws MojoExecutionException - */ - protected void renameAlfrescoGlobalProperties() throws MojoExecutionException { - String alfrescoGlobalFilePath = project.getBuild().getTestOutputDirectory() + "/alfresco-global-"; - if (enableH2) { - alfrescoGlobalFilePath += "h2.properties"; - getLog().info("Renaming alfresco-global-h2.properties to alfresco-global.properties"); - } else if (enableMySQL) { - alfrescoGlobalFilePath += "mysql.properties"; - getLog().info("Renaming alfresco-global-mysql.properties to alfresco-global.properties"); - } else if (enablePostgreSQL) { - alfrescoGlobalFilePath += "postgresql.properties"; - getLog().info("Renaming alfresco-global-postgresql.properties to alfresco-global.properties"); - } else if (enableEnterpriseDb) { - alfrescoGlobalFilePath += "enterprise.properties"; - getLog().info("Renaming alfresco-global-enterprise.properties to alfresco-global.properties"); - } else { - throw new MojoExecutionException("Invalid database configuration, use enableH2, enableMySQL, " + - "enablePostgreSQL, or enabaleEnterpriseDb"); - } - - if (!FileUtils.fileExists(alfrescoGlobalFilePath)) { - throw new MojoExecutionException("Missing file: " + alfrescoGlobalFilePath + ", when converting from older " + - "SDK versions generate an SDK 3 AIO or Platform JAR project and copy " + - "alfresco-global-*.properties files from it. Then configure any custom settings from old SDK " + - "project repo/src/main/properties/local/alfresco-global.properties file in the new " + - "alfresco-global-h2.properties file, or other config file corresponding to the database you are using."); - } - - executeMojo( - plugin( - groupId("com.coderplus.maven.plugins"), - artifactId("copy-rename-maven-plugin"), - version("1.0") - ), - goal("rename"), - configuration( - element(name("sourceFile"), alfrescoGlobalFilePath), - element(name("destinationFile"), "${project.build.testOutputDirectory}/alfresco-global.properties") - ), - execEnv - ); - } - - /** - * Copy the Alfresco Enterprise license to its correct place in the Platform WAR, if it exists. - * It is not enough to have it on the test classpath, then it will start up as Trial license... - * - * @throws MojoExecutionException - */ - protected void copyAlfrescoLicense() throws MojoExecutionException { - if (alfrescoEdition.equals(ALFRESCO_COMMUNITY_EDITION)) { - getLog().info("NOT copying Alfresco Enterprise license, running Community edition"); - return; - } - - final String warOutputDir = getWarOutputDir(PLATFORM_WAR_PREFIX_NAME); - final String licDestDir = warOutputDir + "/WEB-INF/classes/alfresco/extension/license"; - - getLog().info("Copying Alfresco Enterprise license to: " + licDestDir); - - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-resources-plugin"), - version(MAVEN_RESOURCE_PLUGIN_VERSION) - ), - goal("copy-resources"), - configuration( - element(name("outputDirectory"), licDestDir), - element(name("resources"), - element(name("resource"), - element(name("directory"), "src/test/license"), - element(name("includes"), - element(name("include"), "*.lic") - ), - element(name("filtering"), "false") - ) - ) - ), - execEnv - ); - } - - /** - * Copy the Activiti Log4J Dev config into the activitiApp-war/WEB-INF/classes dir. - * - * @throws MojoExecutionException - */ - protected void copyActivitiLog4JDevConfig() throws MojoExecutionException { - final String warOutputDir = getWarOutputDir(ACTIVITI_APP_WAR_PREFIX_NAME); - final String logConfDestDir = warOutputDir + "/WEB-INF/classes"; - - getLog().info("Copying Activiti log4j-dev.properties to: " + logConfDestDir); - - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-resources-plugin"), - version(MAVEN_RESOURCE_PLUGIN_VERSION) - ), - goal("copy-resources"), - configuration( - element(name("outputDirectory"), logConfDestDir), - element(name("resources"), - element(name("resource"), - element(name("directory"), "src/test/resources"), - element(name("includes"), - element(name("include"), "log4j-dev.properties") - ), - element(name("filtering"), "true") - ) - ) - ), - execEnv - ); - } - - /** - * Copy a custom Share Log4J config into the share-war/WEB-INF/classes dir. - * There is no custom classpath resolve mechanism for Share log4j, - * to log custom stuff overriding standard log4j.properties is needed. - * - * @throws MojoExecutionException - */ - protected void copyShareLog4jConfig() throws MojoExecutionException { - if (!useCustomShareLog4jConfig) { - getLog().info("NOT overriding share/WEB-INF/classes/log4j.properties"); - return; - } - - final String warOutputDir = getWarOutputDir(SHARE_WAR_PREFIX_NAME); - final String logConfDestDir = warOutputDir + "/WEB-INF/classes"; - - getLog().info("Copying Share log4j.properties to: " + logConfDestDir); - - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-resources-plugin"), - version(MAVEN_RESOURCE_PLUGIN_VERSION) - ), - goal("copy-resources"), - configuration( - element(name("outputDirectory"), logConfDestDir), - element(name("resources"), - element(name("resource"), - element(name("directory"), "src/test/resources/share"), - element(name("includes"), - element(name("include"), "log4j.properties") - ), - element(name("filtering"), "true") - ) - ) - ), - execEnv - ); - } - - /** - * Build the customized Platform webapp (i.e. the Repository, alfresco.war) - * that should be deployed by Tomcat by applying all AMPs and JARs from - * the {@code } configuration. - */ - protected void buildPlatformWar() throws MojoExecutionException { - buildCustomWarInDir(PLATFORM_WAR_PREFIX_NAME, platformModules, - alfrescoGroupId, getPlatformWarArtifactId(), alfrescoPlatformVersion); - - commentOutSecureCommsInPlatformWebXml(); - copyAlfrescoLicense(); - - String platformWarArtifactId = packageAndInstallCustomWar(PLATFORM_WAR_PREFIX_NAME); - - // Set up the custom platform war to be run by Tomcat plugin - runnerAlfrescoGroupId = "${project.groupId}"; - runnerAlfrescoPlatformWarArtifactId = platformWarArtifactId; - runnerAlfrescoPlatformVersion = "${project.version}"; - } - - /** - * Build the customized Share webapp (i.e. the share.war) - * that should be deployed by Tomcat by applying all AMPs and JARs from - * the {@code } configuration. - */ - protected void buildShareWar() throws MojoExecutionException { - buildCustomWarInDir(SHARE_WAR_PREFIX_NAME, shareModules, - alfrescoGroupId, alfrescoShareWarArtifactId, alfrescoShareVersion); - - copyShareLog4jConfig(); - - String shareWarArtifactId = packageAndInstallCustomWar(SHARE_WAR_PREFIX_NAME); - - // Set up the custom share war to be run by Tomcat plugin - runnerAlfrescoGroupId = "${project.groupId}"; - runnerAlfrescoShareWarArtifactId = shareWarArtifactId; - runnerAlfrescoShareVersion = "${project.version}"; - } - - /** - * Build the customized Activiti App webapp (i.e. the activiti-app.war) - * that should be deployed by Tomcat by applying all JARs from - * the {@code } configuration. - */ - protected void buildActivitiAppWar() throws MojoExecutionException { - buildCustomWarInDir(ACTIVITI_APP_WAR_PREFIX_NAME, activitiModules, - activitiGroupId, activitiAppWarArtifactId, activitiVersion); - - copyActivitiLog4JDevConfig(); - - String activitiAppWarArtifactId = packageAndInstallCustomWar(ACTIVITI_APP_WAR_PREFIX_NAME); - - // Set up the custom share war to be run by Tomcat plugin - runnerActivitiAppGroupId = "${project.groupId}"; - runnerActivitiAppWarArtifactId = activitiAppWarArtifactId; - runnerActivitiAppVersion = "${project.version}"; - } - - /** - * Build a customized webapp in a directory, - * applying a number of AMPs and/or JARs from alfresco maven plugin configuration. - * - * @param warName the name of the custom war - * @param modules the modules that should be applied to the custom war - * @param originalWarGroupId the Maven groupId for the original war file that should be customized - * @param originalWarArtifactId the Maven artifactId for the original war file that should be customized - * @param originalWarVersion the Maven version for the original war file that should be customized - * @throws MojoExecutionException - */ - protected void buildCustomWarInDir(String warName, - List modules, - String originalWarGroupId, - String originalWarArtifactId, - String originalWarVersion) throws MojoExecutionException { - final String warOutputDir = getWarOutputDir(warName); - final String ampsModuleDir = "modules/" + warName + "/amps"; - final String ampsOutputDir = "${project.build.directory}/" + ampsModuleDir; - List ampModules = new ArrayList<>(); - List jarModules = new ArrayList<>(); - - if (modules != null && modules.size() > 0) { - for (ModuleDependency moduleDep : modules) { - Element el = element(name("artifactItem"), - element(name("groupId"), moduleDep.getGroupId()), - element(name("artifactId"), moduleDep.getArtifactId()), - element(name("version"), moduleDep.getVersion()), - element(name("type"), moduleDep.getType()), - element(name("overWrite"), "true")); - - if (moduleDep.getArtifactId().equalsIgnoreCase("alfresco-share-services")) { - // Skip if we are not running a 5.1 version of Alfresco, 'Alfresco Share Services' - // was not used in earlier versions - if (!isPlatformVersionGtOrEqTo51()) { - continue; - } - } - - if (moduleDep.isAmp()) { - ampModules.add(el); - } else if (moduleDep.isJar()) { - jarModules.add(el); - } else { - throw new MojoExecutionException( - "Unknown module type: " + moduleDep.getType() + - " when building custom " + warName + - " war, only 'jar' and 'amp' types are allowed"); - } - } - } - - // Convert from list to array so we can add these elements below - Element[] ampModuleArray = new Element[ampModules.size()]; - ampModules.toArray(ampModuleArray); - Element[] jarModuleArray = new Element[jarModules.size()]; - jarModules.toArray(jarModuleArray); - - // Unpack the original war to /target/-war - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-dependency-plugin"), - version(MAVEN_DEPENDENCY_PLUGIN_VERSION) - ), - goal("unpack"), - configuration( - element(name("outputDirectory"), warOutputDir), - element(name("artifactItems"), - element(name("artifactItem"), - element(name("groupId"), originalWarGroupId), - element(name("artifactId"), originalWarArtifactId), - element(name("version"), originalWarVersion), - element(name("type"), "war") - ) - ) - ), - execEnv - ); - - if (ampModuleArray.length > 0) { - // Copy AMPs to target/modules//amps so we can install them onto the WAR - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-dependency-plugin"), - version(MAVEN_DEPENDENCY_PLUGIN_VERSION) - ), - goal("copy"), - configuration( - element(name("outputDirectory"), ampsOutputDir), - element(name("artifactItems"), ampModuleArray) - ), - execEnv - ); - - // Then apply all these amps to the unpacked war - // Call the Alfresco Maven Plugin Install Mojo directly, so we don't have to keep SDK version info here - String ampsLocation = project.getBuild().getDirectory() + "/" + ampsModuleDir; - String warLocation = project.getBuild().getDirectory() + "/" + getWarName(warName); - InstallMojo installMojo = new InstallMojo(); - installMojo.setAmpLocation(new File(ampsLocation)); - installMojo.setWarLocation(new File(warLocation)); - installMojo.setForce(true); - try { - installMojo.execute(); - } catch (MojoFailureException e) { - e.printStackTrace(); - } - } - - // Then copy all JAR dependencies to the unpacked war /target/-war/WEB-INF/lib - if (jarModuleArray.length > 0) { - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-dependency-plugin"), - version(MAVEN_DEPENDENCY_PLUGIN_VERSION) - ), - goal("copy"), - configuration( - element(name("outputDirectory"), warOutputDir + "/WEB-INF/lib"), - element(name("artifactItems"), jarModuleArray) - ), - execEnv - ); - } - } - - /** - * Package customized war file and install it in local maven repo. - * - * @param warName the name of the custom war - * @return the customized war file artifactId, to be used by the tomcat7 plugin - * @throws MojoExecutionException - */ - protected String packageAndInstallCustomWar(String warName) throws MojoExecutionException { - final String warArtifactId = "${project.artifactId}-" + warName; - final String warSourceDir = getWarOutputDir(warName); - - // Package the customized war file - // Note. don't use the maven-war-plugin here as it will package the module files twice, once from the - // target/classes dir and once via the JAR - String warPath = project.getBuild().getDirectory() + "/" + warName + ".war"; - ZipUtil.pack(new File(warSourceDir), new File(warPath)); - - // Install the customized war file in the local maven repo - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-install-plugin"), - version(MAVEN_INSTALL_PLUGIN_VERSION) - ), - goal("install-file"), - configuration( - element(name("file"), warPath), - element(name("groupId"), "${project.groupId}"), - element(name("artifactId"), warArtifactId), - element(name("version"), "${project.version}"), - element(name("packaging"), "war") // Don't forget, otherwise installed as .POM - ) - , execEnv - ); - - return warArtifactId; - } - - /** - * Check that a database configuration has been supplied correctly - */ - private void checkDatabaseConfig() throws MojoExecutionException { - // Only do this check if we are running alfresco.war or activiti-app.war that needs a database. - if (enablePlatform || enableActivitiApp) { - if (enableH2 && !enableMySQL && !enablePostgreSQL) { - // Run with the H2 database - return; - } else if (!enableH2 && enableMySQL && !enablePostgreSQL) { - // Run with the MySQL database - return; - } else if (!enableH2 && !enableMySQL && enablePostgreSQL) { - // Run with the PostgreSQL database - return; - } else if (!enableH2 && !enableMySQL && !enablePostgreSQL) { - // Run with a database configured via Tomcat Dependencies - return; - } else { - throw new MojoExecutionException( - "Invalid database configuration, " + - "should be enableH2 or enableMySQL or enablePostgreSQL " + - "or none (i.e. config via Tomcat Dependencies)"); - } - } - } - - /** - * Start up the embedded Tomcat server with the webapps that has been - * configured in the SDK project. - * - * @throws MojoExecutionException - */ - protected void startTomcat() throws MojoExecutionException { - getLog().info("Starting Tomcat"); - - List tomcatPluginDependencies = new ArrayList(); - ArrayList webapps2Deploy = new ArrayList(); - - // Add the basic Tomcat dependencies - tomcatPluginDependencies.add( - // Packaging goes faster with this lib - dependency("org.codehaus.plexus", "plexus-archiver", "2.3")); - tomcatPluginDependencies.add( - // The following dependency is needed, otherwise you get - // Caused by: java.lang.NoSuchMethodError: - // javax.servlet.ServletContext.getSessionCookieConfig()Ljavax/servlet/SessionCookieConfig - // This method is in Servlet API 3.0 - dependency("javax.servlet", "javax.servlet-api", "3.0.1")); - - // Do we have any extra Tomcat Plugin dependencies to include? - if (tomcatDependencies != null && tomcatDependencies.size() > 0) { - for (TomcatDependency tomcatDep : tomcatDependencies) { - tomcatPluginDependencies.add( - dependency(tomcatDep.getGroupId(), tomcatDep.getArtifactId(), tomcatDep.getVersion())); - } - } - - if (enableH2) { - tomcatPluginDependencies.add( - // Bring in the flat file H2 database - dependency("com.h2database", "h2", "1.4.190")); - - if (enablePlatform) { - // Copy the h2 scripts for the Alfresco Repository database - copyH2Dialect(); - } - } else if (enableMySQL) { - tomcatPluginDependencies.add( - // Bring in the MySQL JDBC Driver - dependency("mysql", "mysql-connector-java", "5.1.32")); - } else if (enablePostgreSQL) { - tomcatPluginDependencies.add( - // Bring in the PostgreSQL JDBC Driver - dependency("org.postgresql", "postgresql", "9.4-1201-jdbc41")); - } - - if (enablePlatform) { - webapps2Deploy.add(createWebAppElement( - runnerAlfrescoGroupId, runnerAlfrescoPlatformWarArtifactId, runnerAlfrescoPlatformVersion, - "/alfresco", null)); - } - - if (enableShare) { - webapps2Deploy.add(createWebAppElement( - runnerAlfrescoGroupId, runnerAlfrescoShareWarArtifactId, runnerAlfrescoShareVersion, - shareContextPath, null)); - } - - if (enableSolr) { - webapps2Deploy.add(getSolrWebappElement()); - } - - if (enableApiExplorer) { - webapps2Deploy.add(createWebAppElement( - alfrescoGroupId, alfrescoApiExplorerArtifactId, alfrescoApiExplorerVersion, - "/api-explorer", null)); - } - - if (enableActivitiApp) { - webapps2Deploy.add(createWebAppElement( - runnerActivitiAppGroupId, runnerActivitiAppWarArtifactId, runnerActivitiAppVersion, - "/activiti-app", null)); - } - - if (enableActivitiAdmin) { - webapps2Deploy.add(createWebAppElement( - activitiGroupId, activitiAdminWarArtifactId, activitiVersion, "/activiti-admin", null)); - } - - if (tomcatCustomWebapps != null && !tomcatCustomWebapps.isEmpty()) { - // We got extra custom webapps to deploy - for (TomcatWebapp customWebapp: tomcatCustomWebapps) { - webapps2Deploy.add(createWebAppElement( - customWebapp.getGroupId(), customWebapp.getArtifactId(), customWebapp.getVersion(), - customWebapp.getContextPath(), customWebapp.getContextFile())); - } - } - - // This might be ugly, the MojoExecuter will only accept Element[] and we need this list to be dynamic - // to avoid NPEs. If there's a better way to do this, then feel free to change it! - Element[] webapps = new Element[webapps2Deploy.size()]; - webapps2Deploy.toArray(webapps); - - // Set up the system properties that should be set for Tomcat - ArrayList systemProps = new ArrayList(); - systemProps.add(element(name("java.io.tmpdir"), "${project.build.directory}")); - if (enableSolr) { - systemProps.add(element(name("solr.solr.home"), solrHome)); - } - if (enableActivitiApp) { - // Should be in activiti-jar/src/test/resources - systemProps.add(element(name("log4j.configuration"), "log4j-dev.properties")); - } - // Add custom system properties defined in plugin config - if (tomcatSystemProperties != null && !tomcatSystemProperties.isEmpty()) { - for (Map.Entry sysProp : tomcatSystemProperties.entrySet()) { - systemProps.add(element(name(sysProp.getKey()), sysProp.getValue())); - } - } - // This might be ugly, the MojoExecuter will only accept Element[] and we need this list to be dynamic - // to avoid NPEs. If there's a better way to do this, then feel free to change it! - Element[] systemPropArray = new Element[systemProps.size()]; - systemProps.toArray(systemPropArray); - - executeMojo( - plugin( - groupId("org.apache.tomcat.maven"), - artifactId("tomcat7-maven-plugin"), - version(MAVEN_TOMCAT7_PLUGIN_VERSION), - tomcatPluginDependencies - ), - goal("run"), - configuration( - /* - * SDK Projects doesn't have packaging set to 'war', they are JARs or POMs, - * this setting ignores that fact. - */ - element(name("ignorePackaging"), "true"), - - /* - * Make sure Catalina classes are picked up when we got virtual webapp contexts with classpaths. - * - * If true a new classLoader separated from maven core will be created to start. - * This does not work to run with, getting : - * NoSuchMethodError: javax.servlet.ServletContext.getSessionCookieConfig - * (which lives in Servlet API 3) - * - */ - element(name("useSeparateTomcatClassLoader"), "true"), - - /* - * Bring in stuff in the test classpath, such as the alfresco-global.properties - * that should be used - */ - element(name("useTestClasspath"), "true"), - - /** - * Set up where Solr Home directory is - */ - element(name("systemProperties"), systemPropArray), - - /* Should this class loader delegate to the parent class loader before searching its - own repositories (i.e. the usual Java2 delegation model). - Prevent parent classloader delegation, each webapp loads. - If set to true then you will get a truckload of Solr logging as - the alf_data_dev/solr4/config/log4j-solr.properties file is not picked up. - This also fixes issues with the Google Guava Library, which this tomcat plugin uses - version 10.0.1 of but Solr uses 14.0.1 */ - element(name("delegate"), "false"), - - /* - * Encode url in UTF-8 for proper character handling --> - */ - element(name("uriEncoding"), "UTF-8"), - - /* - * Bring in the webapps that should be deployed and run - */ - element(name("webapps"), webapps) - - ), - execEnv - ); - } - - /** - * Create a webapp element that can be added as a webapp configuration to the Tomcat plug-in. - *

- * For example: - *

-     *    {@code
-     *    
-     *        ${project.groupId}
-     *        share
-     *        ${project.version}
-     *        war
-     *        true
-     *        /share
-     *        ${project.build.directory}/contexts/context-share.xml
-     *    
-     *    }
-     * 
- * - * @param groupId - * @param artifactId - * @param version - * @param contextPath - * @param contextFile - * @return - */ - private Element createWebAppElement(String groupId, - String artifactId, - String version, - String contextPath, - String contextFile) { - String errorStr = "cannot be null when creating webapp element for Tomcat 7 plugin"; - if (StringUtils.isBlank(groupId)) { - getLog().error("Maven Group Id " + errorStr); - } - if (StringUtils.isBlank(artifactId)) { - getLog().error("Maven Artifact Id " + errorStr); - } - if (StringUtils.isBlank(version)) { - getLog().error("Maven Version number " + errorStr); - } - - Element groupIdEl = element(name("groupId"), groupId); - Element artifactIdEl = element(name("artifactId"), artifactId); - Element versionEl = element(name("version"), version); - Element typeEl = element(name("type"), "war"); - // Make sure webapp is loaded with context and everything, - // if set to 'false' then you will get 404 when trying to access the webapp from browser - Element asWebappEl = element(name("asWebapp"), "true"); - Element contextPathEl = element(name("contextPath"), contextPath); - - Element e; - if (StringUtils.isNotBlank(contextFile)) { - e = element(name("webapp"), - groupIdEl, artifactIdEl, versionEl, typeEl, asWebappEl, contextPathEl, - element(name("contextFile"), contextFile)); - - } else { - e = element(name("webapp"), - groupIdEl, artifactIdEl, versionEl, typeEl, asWebappEl, contextPathEl); - } - - getLog().info(e.toDom().toUnescapedString()); - - return e; - } - - /** - * Returns true if current platform version (i.e. version of alfresco.war) is - * >= 5.1 - * - * @return true if platform version >= 5.1 - */ - private boolean isPlatformVersionGtOrEqTo51() { - if (getPlatformVersionNumber() >= 51) { - return true; - } - - return false; - } - - /** - * Returns true if current platform version (i.e. version of alfresco.war) is - * <= 4.2 - * - * @return true if platform version <= 4.2 - */ - private boolean isPlatformVersionLtOrEqTo42() { - if (getPlatformVersionNumber() <= 42) { - return true; - } - - return false; - } - - /** - * Grabs the first 2 numbers in the version string - * - * @return major and minor version as int, such as 41,50,51 - */ - private int getPlatformVersionNumber() { - return Integer.parseInt(alfrescoPlatformVersion.replaceAll("[^0-9]", "").substring(0, 2)); - } - - /** - * Get the Solr artifactId, it changes when we move to Solr 4 in Alfresco version 5 - * - * @return the Maven artifactId for Solr - */ - private String getSolrArtifactId() { - // artifactId for Solr defaults to version 4 = alfresco-solr4 - - if (isPlatformVersionLtOrEqTo42()) { - // Solr version 1 is used in Alfresco 4.0 -> 4.2, Solr version 4.0 was introduced in Alfresco version 5.0 - alfrescoSolrArtifactId = "alfresco-solr"; - } - - return alfrescoSolrArtifactId; - } - - /** - * Get the Alfresco Platform Webapp artifactId (i.e. for alfresco.war), - * it changes from 'alfresco' to 'alfresco-platform' in 5.1. - * - * @return the Maven artifactId for Alfresco Platform webapp - */ - private String getPlatformWarArtifactId() { - // Default alfrescoPlatformWarArtifactId is 'alfresco-platform' - - if (isPlatformVersionGtOrEqTo51() == false) { - // We are running version 4.2 or 5.0, so use older artifactId - alfrescoPlatformWarArtifactId = "alfresco"; - } else if (alfrescoEdition.equals(ALFRESCO_ENTERPRISE_EDITION)) { - alfrescoPlatformWarArtifactId = "alfresco-enterprise"; - } - - return alfrescoPlatformWarArtifactId; - } - - /** - * Get the Solr webapp element for use by Tomcat, it changes when we move to Solr 4 in Alfresco version 5 - * - * @return tomcat webapp element - */ - private Element getSolrWebappElement() { - Element webappElement = null; - - if (isPlatformVersionLtOrEqTo42()) { - // Solr version 1.0 - webappElement = createWebAppElement("${project.groupId}", getSolrArtifactId(), "${project.version}", - "/solr", "${project.build.testOutputDirectory}/tomcat/context-solr.xml"); - } else { - // Solr version 4.0 - webappElement = createWebAppElement(alfrescoGroupId, getSolrArtifactId(), alfrescoPlatformVersion, - "/solr4", "${project.build.testOutputDirectory}/tomcat/context-solr.xml"); - } - - return webappElement; - } - - /** - * TODO: From 5.1.e and onwards we have the alfresco-repository:h2scripts:jar artifact, so we potentially only need to do this for older than 5.1.e - * - * - * Extract PostgreSQL dialect and ibatis from alfresco-repository, rename to H2Dialect in the test-classes - * - * @return - */ - private void copyH2Dialect() throws MojoExecutionException { - getLog().info("Unpacking DB Dialects and ibatis files from alfresco-repository artifact"); - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-dependency-plugin"), - version(MAVEN_DEPENDENCY_PLUGIN_VERSION) - ), - goal("unpack"), - configuration( - element(name("outputDirectory"), "${project.build.testOutputDirectory}"), - element(name("artifactItems"), - element(name("artifactItem"), - element(name("groupId"), alfrescoGroupId), - element(name("artifactId"), "alfresco-repository"), - element(name("version"), alfrescoPlatformVersion), - element(name("includes"), "alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/dbscripts/upgrade/*/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/*") - ) - ) - ), - execEnv - ); - - // If we're in enterprise we need to make sure we grab everything - if (this.alfrescoEdition.equals(ALFRESCO_ENTERPRISE_EDITION)) { - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-dependency-plugin"), - version(MAVEN_DEPENDENCY_PLUGIN_VERSION) - ), - goal("unpack"), - configuration( - element(name("outputDirectory"), "${project.build.testOutputDirectory}"), - element(name("artifactItems"), - element(name("artifactItem"), - element(name("groupId"), alfrescoGroupId), - element(name("artifactId"), "alfresco-enterprise-repository"), - element(name("version"), alfrescoPlatformVersion), - element(name("includes"), "alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/dbscripts/upgrade/*/org.hibernate.dialect.PostgreSQLDialect/*,alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/*") - ) - ) - ), - execEnv - ); - } - - getLog().info("Copying H2 Dialect SQL create files into target/test-classes"); - executeMojo( - plugin( - groupId("org.apache.maven.plugins"), - artifactId("maven-resources-plugin"), - version(MAVEN_RESOURCE_PLUGIN_VERSION) - ), - goal("copy-resources"), - configuration( - element(name("outputDirectory"), "${project.build.testOutputDirectory}"), - element(name("resources"), - element(name("resource"), - element(name("directory"), "${project.build.testOutputDirectory}/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect"), - element(name("includes"), - element(name("include"), "*") - ), - element(name("targetPath"), "alfresco/dbscripts/create/org.hibernate.dialect.H2Dialect") - ), - element(name("resource"), - element(name("directory"), "${project.build.testOutputDirectory}/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect"), - element(name("includes"), - element(name("include"), "*") - ), - element(name("targetPath"), "alfresco/ibatis/org.hibernate.dialect.H2Dialect") - ) - ) - ), - execEnv - ); - - } - - - /** - * The directory where the custom war will be assembled - * - * @param baseWarName a war base name, such as 'platform' or 'share' - * @return a directory such as: .../aio/target/platform-war - */ - private String getWarOutputDir(String baseWarName) { - return project.getBuild().getDirectory() + "/" + getWarName(baseWarName); - } - - /** - * Get the war filename based on passed in war type - * - * @param baseWarName a war base name, such as 'platform' or 'share' - * @return - */ - private String getWarName(String baseWarName) { - return baseWarName + "-war"; - } } diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/ValidateMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/ValidateMojo.java index c8aa268a..1943a956 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/ValidateMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/ValidateMojo.java @@ -1,7 +1,22 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.alfresco.maven.plugin; -import java.io.File; - import org.alfrescolabs.technical.validation.AlfrescoTechnicalValidation; import org.alfrescolabs.technical.validation.impl.AlfrescoTechnicalValidationImpl; import org.apache.maven.plugin.AbstractMojo; diff --git a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/VersionMojo.java b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/VersionMojo.java index eec0b9d4..234d57fa 100644 --- a/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/VersionMojo.java +++ b/plugins/alfresco-maven-plugin/src/main/java/org/alfresco/maven/plugin/VersionMojo.java @@ -1,3 +1,20 @@ +/** + * Copyright (C) 2017 Alfresco Software Limited. + *

+ * This file is part of the Alfresco SDK. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.alfresco.maven.plugin; import java.text.DateFormat; diff --git a/pom.xml b/pom.xml index 1787d61c..c6e44afa 100644 --- a/pom.xml +++ b/pom.xml @@ -138,7 +138,7 @@ */*-enterprise/* - 5.1.g + 5.2.e https://github.com/Alfresco/alfresco-sdk