001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020 package org.apache.geronimo.plugin.car; 021 022 import java.io.File; 023 import java.io.StringWriter; 024 025 import java.util.Iterator; 026 import java.util.LinkedHashSet; 027 import java.util.List; 028 import java.util.Properties; 029 030 import javax.xml.namespace.QName; 031 032 import org.apache.geronimo.deployment.service.EnvironmentBuilder; 033 import org.apache.geronimo.deployment.xbeans.ArtifactType; 034 import org.apache.geronimo.deployment.xbeans.EnvironmentType; 035 import org.apache.geronimo.kernel.repository.Environment; 036 import org.apache.geronimo.kernel.repository.Artifact; 037 import org.apache.geronimo.kernel.repository.ImportType; 038 039 import org.apache.maven.model.Dependency; 040 041 import org.apache.velocity.Template; 042 import org.apache.velocity.VelocityContext; 043 import org.apache.velocity.app.VelocityEngine; 044 045 import org.apache.xmlbeans.XmlCursor; 046 import org.apache.xmlbeans.XmlObject; 047 import org.apache.xmlbeans.XmlOptions; 048 import org.apache.xmlbeans.XmlCursor.TokenType; 049 050 // 051 // TODO: Rename to PreparePlanMojo 052 // 053 054 /** 055 * Add dependencies to a plan and process with velocity 056 * 057 * @goal prepare-plan 058 * 059 * @version $Rev: 451661 $ $Date: 2006-09-30 13:45:53 -0700 (Sat, 30 Sep 2006) $ 060 */ 061 public class PlanProcessorMojo 062 extends AbstractCarMojo 063 { 064 private static final String ENVIRONMENT_LOCAL_NAME = "environment"; 065 066 private static final QName ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "environment"); 067 068 /** 069 * @parameter expression="${basedir}/src/plan" 070 * @required 071 */ 072 protected File sourceDir = null; 073 074 /** 075 * @parameter expression="${project.build.directory}/plan" 076 * @required 077 */ 078 protected File targetDir = null; 079 080 /** 081 * @parameter default-value="plan.xml" 082 * @required 083 */ 084 protected String planFileName = null; 085 086 /** 087 * @parameter expression="${project.build.directory}/plan/plan.xml" 088 * @required 089 */ 090 protected File targetFile = null; 091 092 private VelocityContext createContext() { 093 VelocityContext context = new VelocityContext(); 094 095 // Load properties, It inherits them all! 096 Properties props = project.getProperties(); 097 for (Iterator iter = props.keySet().iterator(); iter.hasNext();) { 098 String key = (String) iter.next(); 099 String value = props.getProperty(key); 100 101 log.debug("Setting " + key + "=" + value); 102 context.put(key, value); 103 } 104 105 context.put("pom", project); 106 107 return context; 108 } 109 110 protected void doExecute() throws Exception { 111 // 112 // FIXME: Do not need velocity here, we only need to filter, 113 // could use resources plugin to do this for us, or 114 // implement what resources plugin does here 115 // 116 117 VelocityContext context = createContext(); 118 119 VelocityEngine velocity = new VelocityEngine(); 120 velocity.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, sourceDir.getAbsolutePath()); 121 velocity.init(); 122 123 Template template = velocity.getTemplate(planFileName); 124 StringWriter writer = new StringWriter(); 125 template.merge(context, writer); 126 127 String plan = writer.toString(); 128 129 XmlObject doc = XmlObject.Factory.parse(plan); 130 XmlCursor xmlCursor = doc.newCursor(); 131 LinkedHashSet dependencies = toDependencies(); 132 Artifact configId = new Artifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), "car"); 133 134 try { 135 mergeEnvironment(xmlCursor, configId, dependencies); 136 137 if (targetDir.exists()) { 138 if (!targetDir.isDirectory()) { 139 throw new RuntimeException("TargetDir: " + this.targetDir + " exists and is not a directory"); 140 } 141 } 142 else { 143 targetDir.mkdirs(); 144 } 145 146 XmlOptions xmlOptions = new XmlOptions(); 147 xmlOptions.setSavePrettyPrint(); 148 doc.save(targetFile, xmlOptions); 149 150 log.info("Generated: " + targetFile); 151 } 152 finally { 153 xmlCursor.dispose(); 154 } 155 } 156 157 void mergeEnvironment(final XmlCursor xmlCursor, final Artifact configId, final LinkedHashSet dependencies) { 158 moveToFirstStartElement(xmlCursor); 159 160 boolean atLeastOneChild = xmlCursor.toFirstChild(); 161 if (!atLeastOneChild) { 162 // this is an empty element. Move to EndToken such XmlCursor.beginElement inserts an element inside it. 163 xmlCursor.toEndToken(); 164 } 165 QName childName = xmlCursor.getName(); 166 Environment oldEnvironment; 167 168 if (childName != null && childName.getLocalPart().equals(ENVIRONMENT_LOCAL_NAME)) { 169 convertElement(xmlCursor, ENVIRONMENT_QNAME.getNamespaceURI()); 170 XmlObject xmlObject = xmlCursor.getObject(); 171 EnvironmentType environmentType = (EnvironmentType) xmlObject.copy().changeType(EnvironmentType.type); 172 oldEnvironment = EnvironmentBuilder.buildEnvironment(environmentType); 173 xmlCursor.removeXml(); 174 } else { 175 oldEnvironment = new Environment(); 176 } 177 178 Environment newEnvironment = new Environment(); 179 newEnvironment.setConfigId(configId); 180 newEnvironment.setDependencies(dependencies); 181 182 EnvironmentBuilder.mergeEnvironments(oldEnvironment, newEnvironment); 183 EnvironmentType environmentType = EnvironmentBuilder.buildEnvironmentType(oldEnvironment); 184 185 xmlCursor.beginElement(ENVIRONMENT_QNAME); 186 XmlCursor element = environmentType.newCursor(); 187 188 try { 189 element.copyXmlContents(xmlCursor); 190 } 191 finally { 192 element.dispose(); 193 } 194 } 195 196 private void moveToFirstStartElement(XmlCursor xmlCursor) throws AssertionError { 197 xmlCursor.toStartDoc(); 198 xmlCursor.toFirstChild(); 199 while (!xmlCursor.currentTokenType().isStart()) { 200 if (!xmlCursor.toNextSibling()) { 201 break; 202 } 203 } 204 if (!xmlCursor.currentTokenType().isStart()) { 205 throw new AssertionError("Cannot find first start element"); 206 } 207 } 208 209 private void convertElement(final XmlCursor cursor, final String namespace) { 210 cursor.push(); 211 XmlCursor end = cursor.newCursor(); 212 213 try { 214 end.toCursor(cursor); 215 end.toEndToken(); 216 217 while (cursor.hasNextToken() && cursor.isLeftOf(end)) { 218 if (cursor.isStart()) { 219 if (!namespace.equals(cursor.getName().getNamespaceURI())) { 220 cursor.setName(new QName(namespace, cursor.getName().getLocalPart())); 221 } 222 } 223 224 cursor.toNextToken(); 225 } 226 227 cursor.pop(); 228 } 229 finally { 230 end.dispose(); 231 } 232 } 233 234 private LinkedHashSet toDependencies() { 235 List artifacts = project.getDependencies(); 236 LinkedHashSet dependencies = new LinkedHashSet(); 237 238 Iterator iter = artifacts.iterator(); 239 while (iter.hasNext()) { 240 Dependency dependency = (Dependency) iter.next(); 241 242 // 243 // HACK: Does not appear that we can get the "extention" status of a dependency, 244 // so specifically exclude the ones that we know about, like genesis 245 // 246 247 if (dependency.getGroupId().startsWith("org.apache.geronimo.genesis")) { 248 continue; 249 } 250 251 org.apache.geronimo.kernel.repository.Dependency gdep = toGeronimoDependency(dependency); 252 if (gdep != null) { 253 dependencies.add(gdep); 254 } 255 } 256 257 return dependencies; 258 } 259 260 private static org.apache.geronimo.kernel.repository.Dependency toGeronimoDependency(final Dependency dependency) { 261 Artifact artifact = toGeronimoArtifact(dependency); 262 String type = dependency.getType(); 263 String scope = dependency.getScope(); 264 String groupId = dependency.getGroupId(); 265 266 //!"org.apache.geronimo.specs".equals(groupId) jacc spec needed in plan.xml 267 if ("jar".equalsIgnoreCase(type) && !"junit".equals(groupId) && (scope == null || !scope.equals("provided"))) { 268 if (dependency.getVersion() != null) { 269 artifact = new Artifact( 270 artifact.getGroupId(), 271 artifact.getArtifactId(), 272 dependency.getVersion(), 273 artifact.getType()); 274 } 275 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES); 276 } 277 else if ("car".equalsIgnoreCase(type) && ("runtime").equalsIgnoreCase(scope)) { 278 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.SERVICES); 279 } 280 else if ("car".equalsIgnoreCase(type) && ("compile".equalsIgnoreCase(scope))) { 281 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES); 282 } 283 else if ("car".equalsIgnoreCase(type) && (scope == null)) { //parent 284 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.ALL); 285 } 286 else { 287 // not one of ours 288 return null; 289 } 290 } 291 292 private static Artifact toGeronimoArtifact(final Dependency dependency) { 293 String groupId = dependency.getGroupId(); 294 String artifactId = dependency.getArtifactId(); 295 String version = null; 296 String type = dependency.getType(); 297 298 return new Artifact(groupId, artifactId, version, type); 299 } 300 301 interface Inserter { 302 ArtifactType insert(EnvironmentType environmentType); 303 } 304 }