001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.portal.pluto;
018:
019: import java.io.File;
020: import java.io.FileOutputStream;
021: import java.io.FileReader;
022: import java.io.FileWriter;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.util.Collection;
026: import java.util.Enumeration;
027: import java.util.Iterator;
028: import java.util.Locale;
029: import java.util.Vector;
030: import java.util.jar.JarEntry;
031: import java.util.jar.JarFile;
032:
033: import org.apache.cocoon.portal.pluto.factory.ControllerFactoryImpl;
034: import org.apache.cocoon.portal.pluto.om.PortletApplicationDefinitionImpl;
035: import org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistryImpl;
036: import org.apache.cocoon.portal.pluto.om.ServletDefinitionImpl;
037: import org.apache.cocoon.portal.pluto.om.ServletMapping;
038: import org.apache.cocoon.portal.pluto.om.WebApplicationDefinitionImpl;
039: import org.apache.cocoon.portal.pluto.om.common.DescriptionImpl;
040: import org.apache.cocoon.portal.pluto.om.common.DescriptionSetImpl;
041: import org.apache.cocoon.portal.pluto.om.common.DisplayNameImpl;
042: import org.apache.cocoon.portal.pluto.om.common.DisplayNameSetImpl;
043: import org.apache.cocoon.portal.pluto.om.common.TagDefinition;
044: import org.apache.commons.cli.CommandLine;
045: import org.apache.commons.cli.CommandLineParser;
046: import org.apache.commons.cli.HelpFormatter;
047: import org.apache.commons.cli.Option;
048: import org.apache.commons.cli.Options;
049: import org.apache.commons.cli.ParseException;
050: import org.apache.commons.cli.PosixParser;
051: import org.apache.commons.lang.SystemUtils;
052: import org.apache.pluto.om.ControllerFactory;
053: import org.apache.pluto.om.common.Parameter;
054: import org.apache.pluto.om.common.ParameterCtrl;
055: import org.apache.pluto.om.common.ParameterSet;
056: import org.apache.pluto.om.common.ParameterSetCtrl;
057: import org.apache.pluto.om.common.SecurityRoleRef;
058: import org.apache.pluto.om.common.SecurityRoleRefSet;
059: import org.apache.pluto.om.common.SecurityRoleRefSetCtrl;
060: import org.apache.pluto.om.common.SecurityRoleSet;
061: import org.apache.pluto.om.portlet.PortletDefinition;
062: import org.apache.pluto.om.servlet.ServletDefinition;
063: import org.apache.pluto.om.servlet.ServletDefinitionCtrl;
064: import org.apache.pluto.om.servlet.ServletDefinitionListCtrl;
065: import org.apache.xml.serialize.OutputFormat;
066: import org.apache.xml.serialize.XMLSerializer;
067: import org.exolab.castor.mapping.Mapping;
068: import org.exolab.castor.xml.Marshaller;
069: import org.exolab.castor.xml.Unmarshaller;
070: import org.xml.sax.InputSource;
071:
072: /**
073: * First version of a simple portlet deploy tool for the Cocoon Portal.
074: * It works very similar to the deploy tool of the Pluto project (most
075: * code is taken and improved from the Pluto tool!).
076: * The only difference is that this deploy tool does not copy the taglib
077: * definition for the portlet tags, so you have to have these in your
078: * portlet war already!
079: *
080: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
081: *
082: * @version CVS $Id: Deploy.java 30941 2004-07-29 19:56:58Z vgritsenko $
083: */
084: public class Deploy {
085:
086: //attributes for the web.xml creation for portlets
087: public final static String WEB_PORTLET_PUBLIC_ID = "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN";
088: public final static String WEB_PORTLET_DTD = "http://java.sun.com/dtd/web-app_2_3.dtd";
089:
090: private static boolean debug = false;
091: private static final String webInfDir = File.separatorChar
092: + "WEB-INF" + File.separatorChar;
093:
094: /**
095: * Deploy the archive
096: * Unpack the archive in the servlet engine context directory
097: */
098: public static void deployArchive(final String webAppsDir,
099: final String warFile, final String warFileName)
100: throws IOException {
101: System.out.println("Deploying '" + warFileName + "' ...");
102:
103: final String destination = webAppsDir + warFileName;
104:
105: if (debug) {
106: System.out.println(" unpacking '" + warFile + "' ...");
107: }
108: final JarFile jarFile = new JarFile(warFile);
109: final Enumeration files = jarFile.entries();
110: while (files.hasMoreElements()) {
111: JarEntry entry = (JarEntry) files.nextElement();
112:
113: File file = new File(destination, entry.getName());
114: File dirF = new File(file.getParent());
115: dirF.mkdirs();
116: if (entry.isDirectory()) {
117: file.mkdirs();
118: } else {
119: byte[] buffer = new byte[1024];
120: int length = 0;
121: InputStream fis = jarFile.getInputStream(entry);
122: FileOutputStream fos = new FileOutputStream(file);
123: while ((length = fis.read(buffer)) >= 0) {
124: fos.write(buffer, 0, length);
125: }
126: fos.close();
127: }
128:
129: }
130:
131: if (debug) {
132: System.out.println("Finished!");
133: }
134: }
135:
136: /**
137: * Helper method to setup the mapping
138: */
139: private static Mapping getMapping(final String uri)
140: throws IOException {
141: final String mappingResource = uri
142: .substring(uri.indexOf("://") + 2);
143: final Mapping mapping = new Mapping();
144:
145: final InputSource is = new InputSource(Deploy.class
146: .getResourceAsStream(mappingResource));
147: try {
148: mapping.loadMapping(is);
149: } catch (Exception e) {
150: throw new IOException("Failed to load mapping file "
151: + mappingResource);
152: }
153: return mapping;
154: }
155:
156: /**
157: * Prepare the web archive of the portlet web app
158: */
159: public static void prepareWebArchive(String webAppsDir,
160: String webModule) throws Exception {
161: System.out.println("Preparing web archive '" + webModule
162: + "' ...");
163:
164: // get portlet xml mapping file
165: Mapping mappingPortletXml = getMapping(PortletDefinitionRegistryImpl.PORTLET_MAPPING);
166: // get web xml mapping file
167: Mapping mappingWebXml = getMapping(PortletDefinitionRegistryImpl.WEBXML_MAPPING);
168:
169: File portletXml = new File(webAppsDir + webModule + webInfDir
170: + "portlet.xml");
171: File webXml = new File(webAppsDir + webModule + webInfDir
172: + "web.xml");
173:
174: Unmarshaller unmarshaller = new Unmarshaller(mappingPortletXml);
175: PortletApplicationDefinitionImpl portletApp = (PortletApplicationDefinitionImpl) unmarshaller
176: .unmarshal(new FileReader(portletXml));
177:
178: // refill structure with necessary information
179: Vector structure = new Vector();
180: structure.add(webModule);
181: structure.add(null);
182: structure.add(null);
183: portletApp.preBuild(structure);
184:
185: if (debug) {
186: System.out.println(portletApp);
187: }
188:
189: // now generate web part
190:
191: WebApplicationDefinitionImpl webApp = null;
192:
193: if (webXml.exists()) {
194: Unmarshaller unmarshallerWeb = new Unmarshaller(
195: mappingWebXml);
196: unmarshallerWeb.setIgnoreExtraElements(true);
197: webApp = (WebApplicationDefinitionImpl) unmarshallerWeb
198: .unmarshal(new FileReader(webXml));
199: } else {
200: webApp = new WebApplicationDefinitionImpl();
201: DisplayNameImpl dispName = new DisplayNameImpl();
202: dispName.setDisplayName(webModule);
203: dispName.setLocale(Locale.ENGLISH);
204: DisplayNameSetImpl dispSet = new DisplayNameSetImpl();
205: dispSet.add(dispName);
206: webApp.setDisplayNames(dispSet);
207: DescriptionImpl desc = new DescriptionImpl();
208: desc
209: .setDescription("Automated generated Application Wrapper");
210: desc.setLocale(Locale.ENGLISH);
211: DescriptionSetImpl descSet = new DescriptionSetImpl();
212: descSet.add(desc);
213: webApp.setDescriptions(descSet);
214: }
215:
216: ControllerFactory controllerFactory = new ControllerFactoryImpl();
217:
218: ServletDefinitionListCtrl servletDefinitionSetCtrl = (ServletDefinitionListCtrl) controllerFactory
219: .get(webApp.getServletDefinitionList());
220: Collection servletMappings = webApp.getServletMappings();
221:
222: Iterator portlets = portletApp.getPortletDefinitionList()
223: .iterator();
224: while (portlets.hasNext()) {
225:
226: PortletDefinition portlet = (PortletDefinition) portlets
227: .next();
228:
229: if (debug) {
230: System.out.println(" Portlet: " + portlet.getId());
231: }
232: // check if already exists
233: ServletDefinition servlet = webApp
234: .getServletDefinitionList().get(portlet.getName());
235: if (servlet != null) {
236: if (!servlet.getServletClass().equals(
237: "org.apache.pluto.core.PortletServlet")) {
238: System.out
239: .println("Note: Replaced already existing the servlet with the name '"
240: + portlet.getName()
241: + "' with the wrapper servlet.");
242: }
243: ServletDefinitionCtrl _servletCtrl = (ServletDefinitionCtrl) controllerFactory
244: .get(servlet);
245: _servletCtrl
246: .setServletClass("org.apache.pluto.core.PortletServlet");
247: } else {
248: servlet = servletDefinitionSetCtrl.add(portlet
249: .getName(),
250: "org.apache.pluto.core.PortletServlet");
251: }
252:
253: ServletDefinitionCtrl servletCtrl = (ServletDefinitionCtrl) controllerFactory
254: .get(servlet);
255:
256: DisplayNameImpl dispName = new DisplayNameImpl();
257: dispName.setDisplayName(portlet.getName() + " Wrapper");
258: dispName.setLocale(Locale.ENGLISH);
259: DisplayNameSetImpl dispSet = new DisplayNameSetImpl();
260: dispSet.add(dispName);
261: servletCtrl.setDisplayNames(dispSet);
262: DescriptionImpl desc = new DescriptionImpl();
263: desc.setDescription("Automated generated Portlet Wrapper");
264: desc.setLocale(Locale.ENGLISH);
265: DescriptionSetImpl descSet = new DescriptionSetImpl();
266: descSet.add(desc);
267: servletCtrl.setDescriptions(descSet);
268: ParameterSet parameters = servlet.getInitParameterSet();
269:
270: ParameterSetCtrl parameterSetCtrl = (ParameterSetCtrl) controllerFactory
271: .get(parameters);
272:
273: Parameter parameter1 = parameters.get("portlet-class");
274: if (parameter1 == null) {
275: parameterSetCtrl.add("portlet-class", portlet
276: .getClassName());
277: } else {
278: ParameterCtrl parameterCtrl = (ParameterCtrl) controllerFactory
279: .get(parameter1);
280: parameterCtrl.setValue(portlet.getClassName());
281:
282: }
283: Parameter parameter2 = parameters.get("portlet-guid");
284: if (parameter2 == null) {
285: parameterSetCtrl.add("portlet-guid", portlet.getId()
286: .toString());
287: } else {
288: ParameterCtrl parameterCtrl = (ParameterCtrl) controllerFactory
289: .get(parameter2);
290: parameterCtrl.setValue(portlet.getId().toString());
291:
292: }
293:
294: boolean found = false;
295: Iterator mappings = servletMappings.iterator();
296: while (mappings.hasNext()) {
297: ServletMapping servletMapping = (ServletMapping) mappings
298: .next();
299: if (servletMapping.getServletName().equals(
300: portlet.getName())) {
301: found = true;
302: servletMapping.setUrlPattern("/"
303: + portlet.getName().replace(' ', '_')
304: + "/*");
305: }
306: }
307: if (!found) {
308: ServletMapping servletMapping = new ServletMapping();
309: servletMapping.setServletName(portlet.getName());
310: servletMapping.setUrlPattern("/"
311: + portlet.getName().replace(' ', '_') + "/*");
312: servletMappings.add(servletMapping);
313: }
314:
315: SecurityRoleRefSet servletSecurityRoleRefs = ((ServletDefinitionImpl) servlet)
316: .getInitSecurityRoleRefSet();
317:
318: SecurityRoleRefSetCtrl servletSecurityRoleRefSetCtrl = (SecurityRoleRefSetCtrl) controllerFactory
319: .get(servletSecurityRoleRefs);
320:
321: SecurityRoleSet webAppSecurityRoles = webApp
322: .getSecurityRoles();
323:
324: SecurityRoleRefSet portletSecurityRoleRefs = portlet
325: .getInitSecurityRoleRefSet();
326:
327: Iterator p = portletSecurityRoleRefs.iterator();
328:
329: while (p.hasNext()) {
330: SecurityRoleRef portletSecurityRoleRef = (SecurityRoleRef) p
331: .next();
332:
333: if (portletSecurityRoleRef.getRoleLink() == null
334: && webAppSecurityRoles
335: .get(portletSecurityRoleRef
336: .getRoleName()) == null) {
337: System.out
338: .println("Note: The web application has no security role defined which matches the role name \""
339: + portletSecurityRoleRef
340: .getRoleName()
341: + "\" of the security-role-ref element defined for the wrapper-servlet with the name '"
342: + portlet.getName() + "'.");
343: break;
344: }
345: SecurityRoleRef servletSecurityRoleRef = servletSecurityRoleRefs
346: .get(portletSecurityRoleRef.getRoleName());
347: if (null != servletSecurityRoleRef) {
348: System.out
349: .println("Note: Replaced already existing element of type <security-role-ref> with value \""
350: + portletSecurityRoleRef
351: .getRoleName()
352: + "\" for subelement of type <role-name> for the wrapper-servlet with the name '"
353: + portlet.getName() + "'.");
354: servletSecurityRoleRefSetCtrl
355: .remove(servletSecurityRoleRef);
356: }
357: servletSecurityRoleRefSetCtrl
358: .add(portletSecurityRoleRef);
359: }
360:
361: }
362:
363: TagDefinition portletTagLib = new TagDefinition();
364: Collection taglibs = webApp.getCastorTagDefinitions();
365: taglibs.add(portletTagLib);
366:
367: if (debug) {
368: System.out.println(webApp);
369: }
370:
371: OutputFormat of = new OutputFormat();
372: of.setIndenting(true);
373: of.setIndent(4); // 2-space indention
374: of.setLineWidth(16384);
375: // As large as needed to prevent linebreaks in text nodes
376: of.setDoctype(WEB_PORTLET_PUBLIC_ID, WEB_PORTLET_DTD);
377:
378: FileWriter writer = new FileWriter(webAppsDir + webModule
379: + SystemUtils.FILE_SEPARATOR + "WEB-INF"
380: + SystemUtils.FILE_SEPARATOR + "web.xml");
381: XMLSerializer serializer = new XMLSerializer(writer, of);
382: try {
383: Marshaller marshaller = new Marshaller(serializer
384: .asDocumentHandler());
385: marshaller.setMapping(mappingWebXml);
386: marshaller.marshal(webApp);
387: } finally {
388: writer.close();
389: }
390:
391: if (debug) {
392: System.out.println("Finished!");
393: }
394: }
395:
396: public static void main(String args[]) {
397: String warFile;
398: String webAppsDir;
399:
400: final Options options = new Options();
401:
402: Option o;
403: o = new Option("w", true, "webapps directory");
404: o.setRequired(true);
405: o.setArgName("WEBAPPS_DIR");
406: options.addOption(o);
407:
408: o = new Option("p", true,
409: "web archive containing the portlet(s)");
410: o.setRequired(true);
411: o.setArgName("PORTLET_WAR");
412: options.addOption(o);
413:
414: options.addOption("d", "debug", false, "Show debug messages.");
415:
416: try {
417: final CommandLineParser parser = new PosixParser();
418: final CommandLine cmd = parser.parse(options, args);
419:
420: // first test/turn on debug
421: debug = cmd.hasOption("d");
422: if (debug) {
423: for (int i = 0; i < args.length; i++) {
424: System.out.println("args[" + i + "]:" + args[i]);
425: }
426: }
427:
428: webAppsDir = cmd.getOptionValue("w");
429: if (!webAppsDir.endsWith(File.separator))
430: webAppsDir += File.separatorChar;
431:
432: //portalImplWebDir = cmd.getOptionValue("X");
433: //if (!portalImplWebDir.endsWith(File.separator))
434: // portalImplWebDir += File.separatorChar;
435:
436: warFile = cmd.getOptionValue("p");
437: } catch (ParseException exp) {
438: HelpFormatter formatter = new HelpFormatter();
439: formatter.printHelp("deploy", options, true);
440: System.exit(1);
441: return;
442: }
443:
444: // let's do some tests on the war file name
445: String warFileName = warFile;
446: if (warFileName.indexOf("/") != -1) {
447: warFileName = warFileName.substring(warFileName
448: .lastIndexOf("/") + 1);
449: }
450: if (warFileName.indexOf(File.separatorChar) != -1) {
451: warFileName = warFileName.substring(warFileName
452: .lastIndexOf(File.separatorChar) + 1);
453: }
454: if (warFileName.endsWith(".war")) {
455: warFileName = warFileName.substring(0, warFileName
456: .lastIndexOf("."));
457: }
458:
459: try {
460: deployArchive(webAppsDir, warFile, warFileName);
461:
462: prepareWebArchive(webAppsDir, warFileName);
463: } catch (Exception e) {
464: e.printStackTrace();
465: System.exit(1);
466: return;
467: }
468: System.exit(0);
469: }
470:
471: }
|