blob: ef07ba9bcc9c93b7c5d07936e94f8ec4814c2856 [file] [log] [blame]
/*
* 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.
*/
package org.apache.servicemix.maven.plugin.jbi;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.servicemix.common.packaging.Consumes;
import org.apache.servicemix.common.packaging.Provides;
import org.codehaus.plexus.util.FileUtils;
/**
* A Mojo used to build the jbi.xml file for a service unit.
*
* @author <a href="pdodds@apache.org">Philip Dodds</a>
* @version $Id: GenerateComponentDescriptorMojo 314956 2005-10-12 16:27:15Z
* brett $
* @goal generate-jbi-service-assembly-descriptor
* @phase generate-resources
* @requiresDependencyResolution runtime
* @description generates the jbi.xml deployment descriptor for a service unit
*/
public class GenerateServiceAssemblyDescriptorMojo extends AbstractJbiMojo {
public static final String JBI_NAMESPACE = "http://java.sun.com/xml/ns/jbi";
public static final String UTF_8 = "UTF-8";
public class Connection {
private Consumes consumes;
private Provides provides;
public Consumes getConsumes() {
return consumes;
}
public void setConsumes(Consumes consumes) {
this.consumes = consumes;
}
public Provides getProvides() {
return provides;
}
public void setProvides(Provides provides) {
this.provides = provides;
}
}
/**
* Whether the jbi.xml should be generated or not.
*
* @parameter
*/
private Boolean generateJbiDescriptor = Boolean.TRUE;
/**
* The component name.
*
* @parameter expression="${project.artifactId}"
*/
private String name;
/**
* The component description.
*
* @parameter expression="${project.name}"
*/
private String description;
/**
* Character encoding for the auto-generated application.xml file.
*
* @parameter
*/
private String encoding = UTF_8;
/**
* Directory where the application.xml file will be auto-generated.
*
* @parameter expression="${project.build.directory}/classes/META-INF"
*/
private String generatedDescriptorLocation;
/**
* The location of a file containing the connections elements that can be
* merged into the jbi.xml
*
* @parameter expression="${basedir}/src/main/resources/jbi-connections.xml"
*/
private File jbiConnectionsFile;
/**
* Dependency graph
*/
private JbiResolutionListener listener;
public void execute() throws MojoExecutionException, MojoFailureException {
getLog()
.debug(
" ======= GenerateServiceAssemlbyDescriptorMojo settings =======");
getLog().debug("workDirectory[" + workDirectory + "]");
getLog().debug("generateJbiDescriptor[" + generateJbiDescriptor + "]");
getLog().debug("name[" + name + "]");
getLog().debug("description[" + description + "]");
getLog().debug("encoding[" + encoding + "]");
getLog().debug(
"generatedDescriptorLocation[" + generatedDescriptorLocation
+ "]");
if (!generateJbiDescriptor.booleanValue()) {
getLog().debug("Generation of jbi.xml is disabled");
return;
}
// Generate jbi descriptor and copy it to the build directory
getLog().info("Generating jbi.xml");
try {
listener = resolveProject();
generateJbiDescriptor();
} catch (JbiPluginException e) {
throw new MojoExecutionException("Failed to generate jbi.xml", e);
}
try {
FileUtils.copyFileToDirectory(new File(generatedDescriptorLocation,
JBI_DESCRIPTOR), new File(getWorkDirectory(), META_INF));
} catch (IOException e) {
throw new MojoExecutionException(
"Unable to copy jbi.xml to final destination", e);
}
}
/**
* Generates the deployment descriptor if necessary.
*
* @throws MojoExecutionException
*/
protected void generateJbiDescriptor() throws JbiPluginException,
MojoExecutionException {
File outputDir = new File(generatedDescriptorLocation);
if (!outputDir.exists()) {
outputDir.mkdirs();
}
File descriptor = new File(outputDir, JBI_DESCRIPTOR);
List serviceUnits = new ArrayList();
Set artifacts = project.getArtifacts();
for (Iterator iter = artifacts.iterator(); iter.hasNext();) {
Artifact artifact = (Artifact) iter.next();
// TODO: utilise appropriate methods from project builder
ScopeArtifactFilter filter = new ScopeArtifactFilter(
Artifact.SCOPE_RUNTIME);
if (!artifact.isOptional() && filter.include(artifact)
&& (artifact.getDependencyTrail().size() == 2)) {
MavenProject project = null;
try {
project = projectBuilder.buildFromRepository(artifact,
remoteRepos, localRepo);
} catch (ProjectBuildingException e) {
getLog().warn(
"Unable to determine packaging for dependency : "
+ artifact.getArtifactId()
+ " assuming jar");
}
if ((project != null)
&& (project.getPackaging().equals("jbi-service-unit"))) {
DependencyInformation info = new DependencyInformation();
info.setName(artifact.getArtifactId());
String fileName = artifact.getFile().getName();
if (fileName == null) {
// the name is not defined in the POM
// try to use the artifactId
// as the artifactId is mandatory by maven, we don't
// need any additional test
fileName = artifact.getArtifactId();
}
if (fileName.equals("classes")) {
fileName = artifact.getArtifactId() + "-" + artifact.getVersion() + ".jar";
}
String suName = getServiceUnitName(project);
if (suName != null && suName.length() > 0) {
fileName = suName;
} else {
fileName = fileName.substring(0, fileName.lastIndexOf('.')) + ".zip";
}
info.setFilename(fileName);
info.setComponent(getComponentName(project, artifacts, artifact));
info.setDescription(project.getDescription());
serviceUnits.add(info);
}
}
}
List orderedServiceUnits = reorderServiceUnits(serviceUnits);
List connections = getConnections();
JbiServiceAssemblyDescriptorWriter writer = new JbiServiceAssemblyDescriptorWriter(
encoding);
writer.write(descriptor, name, description, orderedServiceUnits,
connections);
}
/**
* Used to return a list of connections if they have been found in the
* jbiConnectionsFile
*
* @return A list of connections
* @throws MojoExecutionException
*/
private List getConnections() throws MojoExecutionException {
if (jbiConnectionsFile.exists()) {
return parseConnectionsXml();
} else {
return new ArrayList();
}
}
/**
* Parse the jbiConnectionsFile
*
* @return
* @throws MojoExecutionException
*/
private List parseConnectionsXml() throws MojoExecutionException {
getLog().info(
"Picking up connections from "
+ jbiConnectionsFile.getAbsolutePath());
List connections = new ArrayList();
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(jbiConnectionsFile);
Node servicesNode = doc.getFirstChild();
if (servicesNode instanceof Element
&& XmlDescriptorHelper.isElement(servicesNode, JBI_NAMESPACE, "connections")) {
// We will process the children
Element servicesElement = (Element) servicesNode;
NodeList children = servicesElement.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
if (XmlDescriptorHelper.isElement(children.item(i), JBI_NAMESPACE, "connection")) {
Connection connection = new Connection();
NodeList connectionChildren = children.item(i).getChildNodes();
for (int x = 0; x < connectionChildren.getLength(); x++) {
if (connectionChildren.item(x) instanceof Element) {
Element childElement = (Element) connectionChildren.item(x);
if (XmlDescriptorHelper.isElement(
childElement, JBI_NAMESPACE, "consumer")) {
Consumes newConsumes = new Consumes();
newConsumes.setEndpointName(XmlDescriptorHelper
.getEndpointName(childElement));
newConsumes.setInterfaceName(XmlDescriptorHelper
.getInterfaceName(childElement));
newConsumes.setServiceName(XmlDescriptorHelper
.getServiceName(childElement));
connection.setConsumes(newConsumes);
} else if (XmlDescriptorHelper.isElement(
childElement, JBI_NAMESPACE, "provider")) {
Provides newProvides = new Provides();
newProvides.setEndpointName(XmlDescriptorHelper
.getEndpointName(childElement));
newProvides.setInterfaceName(XmlDescriptorHelper
.getInterfaceName(childElement));
newProvides.setServiceName(XmlDescriptorHelper
.getServiceName(childElement));
connection.setProvides(newProvides);
}
}
}
connections.add(connection);
}
}
}
getLog().info("Found " + connections.size() + " connections");
return connections;
} catch (Exception e) {
throw new MojoExecutionException("Unable to parse "
+ jbiConnectionsFile.getAbsolutePath());
}
}
/**
* Re-orders the service units to match order in the dependencies section of
* the pom
*
* @param serviceUnits
* @throws MojoExecutionException
*/
private List reorderServiceUnits(List serviceUnits) throws MojoExecutionException {
// TODO Currently we get the model back by re-parsing it however in the
// future we should be able to use the getModel() - there should be a
// fix post 2.0.4
// Iterator dependencies =
// project.getModel().getDependencies().iterator();
// For now we will need to reparse the pom without processing
Iterator dependencies = getReparsedDependencies();
List orderedServiceUnits = new ArrayList();
parseDependencies(serviceUnits, dependencies, orderedServiceUnits);
//get chance the go through the active profile dependencies so that the SU dependency
//from active profile can also be taken into account
List activeProfileList = project.getActiveProfiles();
for (Iterator iter = activeProfileList.iterator(); iter.hasNext();) {
Profile activeProfile = (Profile) iter.next();
parseDependencies(serviceUnits, activeProfile.getDependencies().iterator(), orderedServiceUnits);
}
return orderedServiceUnits;
}
private void parseDependencies(List serviceUnits, Iterator dependencies,
List orderedServiceUnits) throws MojoExecutionException {
while (dependencies.hasNext()) {
Dependency dependency = (Dependency) dependencies.next();
if (dependency.getArtifactId().contains("${")) {
int first = dependency.getArtifactId().indexOf("${");
int last = dependency.getArtifactId().indexOf("}");
String property = dependency.getArtifactId().substring(first + 2, last);
Object propValue = project.getProperties().get(property);
if (propValue == null) {
throw new MojoExecutionException("The value for the property " + property + "is not set."
+ "Jbi descriptor may not be generated properly");
}
String propString = (String) propValue;
String artifactID = dependency.getArtifactId().replace("${" + property + "}", propString);
dependency.setArtifactId(artifactID);
}
for (Iterator it = serviceUnits.iterator(); it.hasNext();) {
DependencyInformation serviceUnitInfo = (DependencyInformation) it
.next();
if (dependency.getArtifactId()
.equals(serviceUnitInfo.getName())) {
//check if this su already added to descriptor
boolean addedSu = false;
for (Iterator innerIt = orderedServiceUnits.iterator();innerIt.hasNext();) {
DependencyInformation addedServiceUnitInfo = (DependencyInformation) innerIt.next();
if (addedServiceUnitInfo.getName().equals(serviceUnitInfo.getName())) {
addedSu = true;
}
}
if (!addedSu) {
getLog().debug("Adding " + serviceUnitInfo.getFilename());
orderedServiceUnits.add(serviceUnitInfo);
}
}
}
}
}
private Iterator getReparsedDependencies() throws MojoExecutionException {
MavenXpp3Reader mavenXpp3Reader = new MavenXpp3Reader();
try {
Model model = mavenXpp3Reader.read(new FileReader(new File(project
.getBasedir(), "pom.xml")), false);
return model.getDependencies().iterator();
} catch (Exception e) {
throw new MojoExecutionException("Unable to reparse the pom.xml");
}
}
private String getComponentName(MavenProject project, Set artifacts,
Artifact suArtifact) throws MojoExecutionException {
getLog().info(
"Determining component name for service unit "
+ project.getArtifactId());
if (project.getProperties().getProperty("componentName") != null) {
return project.getProperties().getProperty("componentName");
}
JbiResolutionListener.Node n = listener.getNode(suArtifact);
for (Iterator it = n.getChildren().iterator(); it.hasNext();) {
JbiResolutionListener.Node child = (JbiResolutionListener.Node) it
.next();
MavenProject artifactProject = null;
try {
getLog().info(child.getArtifact().toString());
artifactProject = projectBuilder
.buildFromRepository(child.getArtifact(),
remoteRepos, localRepo);
} catch (ProjectBuildingException e) {
getLog().warn(
"Unable to determine packaging for dependency : "
+ child.getArtifact().getArtifactId()
+ " assuming jar");
getLog().debug(e);
}
if (artifactProject != null) {
getLog().info(
"Project " + artifactProject + " packaged "
+ artifactProject.getPackaging());
}
if ((artifactProject != null)
&& (artifactProject.getPackaging().equals("jbi-component"))) {
return child.getArtifact().getArtifactId();
}
}
//as the jbi-component packaged dependency may already have been pruned
//in case of multiple sus which belong to same jbi-component exist in one sa, so we
//just check the dependencies from this su maven project to find the jbi-component name
for (Iterator it = project.getArtifacts().iterator(); it.hasNext();) {
Artifact artifactInSUPom = (Artifact) it
.next();
MavenProject artifactProject = null;
try {
artifactProject = projectBuilder.buildFromRepository(artifactInSUPom
, remoteRepos, localRepo);
} catch (ProjectBuildingException e) {
getLog().warn(
"Unable to determine packaging for dependency : "
+ artifactInSUPom.getArtifactId()
+ " assuming jar");
getLog().debug(e);
}
if (artifactProject != null) {
getLog().info(
"Project " + artifactProject + " packaged "
+ artifactProject.getPackaging());
}
if ((artifactProject != null)
&& (artifactProject.getPackaging().equals("jbi-component"))) {
return artifactInSUPom.getArtifactId();
}
}
throw new MojoExecutionException(
"The service unit "
+ project.getArtifactId()
+ " does not have a dependency which is packaged as a jbi-component or a project property 'componentName'");
}
}