/* =============================================================================== * * Part of the InfoGlue Content Management Platform (www.infoglue.org) * * =============================================================================== * * Copyright (C) * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2, as published by the * Free Software Foundation. See the file LICENSE.html for more information. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple * Place, Suite 330 / Boston, MA 02111-1307 / USA. * * =============================================================================== */ package org.infoglue.deliver.portal.deploy; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.Enumeration; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pluto.PortletContainerServices; import org.apache.pluto.descriptors.services.PortletAppDescriptorService; import org.apache.pluto.descriptors.services.WebAppDescriptorService; import org.apache.pluto.descriptors.services.impl.AbstractWebAppDescriptorService; import org.apache.pluto.descriptors.services.impl.StreamPortletAppDescriptorServiceImpl; import org.apache.pluto.om.portlet.PortletApplicationDefinition; import org.apache.pluto.portalImpl.om.portlet.impl.PortletApplicationDefinitionImpl; import org.apache.pluto.portalImpl.services.ServiceManager; import org.apache.xerces.parsers.DOMParser; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.xml.Unmarshaller; import org.infoglue.deliver.portal.ServletConfigContainer; import org.w3c.dom.Document; import org.xml.sax.InputSource; /** * Slightly modified version of jakarta-plutos deploy target. This utility * requires that portletdefinitionmapping.xml and servletdefinitionmapping.xml * are located somewhere in the classpath. */ public class Deploy { public static class StreamWebAppDescriptorServiceImpl extends AbstractWebAppDescriptorService { private InputStream in; private OutputStream out; public StreamWebAppDescriptorServiceImpl(String contextPath, InputStream in, OutputStream out) { super(contextPath); this.in = in; this.out = out; } protected InputStream getInputStream() throws IOException { return in; } protected OutputStream getOutputStream() throws IOException { return out; } } private static final Log log = LogFactory.getLog(Deploy.class); private static final int MAX_POLL_DEPLOY = 30; private static final String PORTLET_XML = "WEB-INF/portlet.xml"; private static final String WEB_XML = "WEB-INF/web.xml"; private static final String PORTLET_MAPPING = "portletdefinitionmapping.xml"; /** * Deploy a portlet. Creates a .war-file in webapps and waits until it is * deployed by the servlet container (max 30 seconds). * * @param webappsDir * webapps directory * @param warName * name of .war-file (portlet) * @param is * stream of .war-file * @param containerName * name of portlet container to be updated * @return true if portlet was deployed * @throws FileNotFoundException * in case webapps directory not found * @throws IOException */ public static boolean deployArchive(String webappsDir, String warName, InputStream is, String containerName) throws FileNotFoundException, IOException { File webapps = new File(webappsDir); if (!webapps.exists() || !webapps.isDirectory()) { throw new FileNotFoundException("Webapps directory not found: " + webappsDir); } String appName = warName; int dot = appName.lastIndexOf("."); if (dot > 0) { appName = appName.substring(0, dot); } else { warName += ".war"; } // Create .war-file in webapps File war = new File(webapps, warName); if (war.exists()) { // .war-file already exists - skip? log.info(".war-file already exists: " + war.getAbsolutePath()); } else { FileOutputStream os = new FileOutputStream(war); BufferedOutputStream bos = new BufferedOutputStream(os); int num = copyStream(is, bos); bos.close(); os.close(); log.info(num + " bytes written to " + war.getAbsolutePath()); } // Expand .war-file into application directory (NOT necessary in Tomcat // 4.1. others?) /* * File appDir = new File(webapps, appName); if (appDir.exists()) { // * app dir already exists - skip? log.warn("Application directory * already exists: " + appDir.getAbsolutePath()); return false; } if * (!appDir.mkdirs()) { throw new IOException( "Unable to create * application directory: " + appDir.getAbsolutePath()); } int numFiles = * expandArchive(war, appDir); log.warn(numFiles + " files extracted to " + * appDir.getAbsolutePath()); */ // Wait until portlet is deployed in servlet container File appDir = new File(webapps, appName); File webInfDir = new File(appDir, "WEB-INF"); File portletXml = new File(webInfDir, "portlet.xml"); for (int i = 0; !portletXml.exists() && i < MAX_POLL_DEPLOY; i++) { log.debug("Waiting for servlet container to deploy portlet, try " + i + "/" + MAX_POLL_DEPLOY); try { Thread.sleep(1000); } catch (InterruptedException e) { log.warn("Deployment paus interrupted", e); } } if (!portletXml.exists()) { log.error("Failed to deploy portlet: " + war.getAbsolutePath()); } // Update pluto service manager log.info("Updating pluto service manager: " + containerName); try { PortletContainerServices.prepare(containerName); ServiceManager.init(ServletConfigContainer.getContainer().getServletConfig()); } catch (Exception e) { log.error("Error during update of pluto service manager", e); } return true; } /** * Prepare a portlet according to Pluto (switch web.xml) * * @param file .war to prepare * @param tmp the resulting updated .war * @param appName name of application (context name) * @return the portlet application definition (portlet.xml) * @throws IOException */ public static PortletApplicationDefinition prepareArchive(File file, File tmp, String appName) throws IOException { PortletApplicationDefinitionImpl portletApp = null; try { Mapping pdmXml = new Mapping(); try { URL url = Deploy.class.getResource("/" + PORTLET_MAPPING); pdmXml.loadMapping(url); } catch (Exception e) { throw new IOException("Failed to load mapping file " + PORTLET_MAPPING); } // Open the jar file. JarFile jar = new JarFile(file); // Extract and parse portlet.xml ZipEntry portletEntry = jar.getEntry(PORTLET_XML); if (portletEntry == null) { throw new IOException("Unable to find portlet.xml"); } InputStream pisDebug = jar.getInputStream(portletEntry); StringBuffer sb = new StringBuffer(); int i; while((i = pisDebug.read()) > -1) { sb.append((char)i); } pisDebug.close(); InputSource xmlSource = new InputSource(new ByteArrayInputStream(sb.toString().getBytes("UTF-8"))); DOMParser parser = new DOMParser(); parser.parse(xmlSource); Document portletDocument = parser.getDocument(); //InputStream pis = jar.getInputStream(portletEntry); //Document portletDocument = XmlParser.parsePortletXml(pis); //pis.close(); InputStream pis = jar.getInputStream(portletEntry); ZipEntry webEntry = jar.getEntry(WEB_XML); InputStream wis = null; if (webEntry != null) { wis = jar.getInputStream(webEntry); /* webDocument = XmlParser.parseWebXml(wis); wis.close(); */ } Unmarshaller unmarshaller = new Unmarshaller(pdmXml); unmarshaller.setWhitespacePreserve(true); unmarshaller.setIgnoreExtraElements(true); unmarshaller.setIgnoreExtraAttributes(true); portletApp = (PortletApplicationDefinitionImpl) unmarshaller.unmarshal(portletDocument); // refill structure with necessary information Vector structure = new Vector(); structure.add(appName); structure.add(null); structure.add(null); portletApp.preBuild(structure); /* // now generate web part WebApplicationDefinitionImpl webApp = null; if (webDocument != null) { Unmarshaller unmarshallerWeb = new Unmarshaller(sdmXml); // modified by YCLI: START :: to ignore extra elements and // attributes unmarshallerWeb.setWhitespacePreserve(true); unmarshallerWeb.setIgnoreExtraElements(true); unmarshallerWeb.setIgnoreExtraAttributes(true); // modified by YCLI: END webApp = (WebApplicationDefinitionImpl) unmarshallerWeb.unmarshal(webDocument); } else { webApp = new WebApplicationDefinitionImpl(); DisplayNameImpl dispName = new DisplayNameImpl(); dispName.setDisplayName(appName); dispName.setLocale(Locale.ENGLISH); DisplayNameSetImpl dispSet = new DisplayNameSetImpl(); dispSet.add(dispName); webApp.setDisplayNames(dispSet); DescriptionImpl desc = new DescriptionImpl(); desc.setDescription("Automated generated Application Wrapper"); desc.setLocale(Locale.ENGLISH); DescriptionSetImpl descSet = new DescriptionSetImpl(); descSet.add(desc); webApp.setDescriptions(descSet); } org.apache.pluto.om.ControllerFactory controllerFactory = new org.apache.pluto.portalImpl.om.ControllerFactoryImpl(); ServletDefinitionListCtrl servletDefinitionSetCtrl = (ServletDefinitionListCtrl) controllerFactory .get(webApp.getServletDefinitionList()); Collection servletMappings = webApp.getServletMappings(); Iterator portlets = portletApp.getPortletDefinitionList().iterator(); while (portlets.hasNext()) { PortletDefinition portlet = (PortletDefinition) portlets.next(); // check if already exists ServletDefinition servlet = webApp.getServletDefinitionList() .get(portlet.getName()); if (servlet != null) { ServletDefinitionCtrl _servletCtrl = (ServletDefinitionCtrl) controllerFactory .get(servlet); _servletCtrl.setServletClass("org.apache.pluto.core.PortletServlet"); } else { servlet = servletDefinitionSetCtrl.add(portlet.getName(), "org.apache.pluto.core.PortletServlet"); } ServletDefinitionCtrl servletCtrl = (ServletDefinitionCtrl) controllerFactory .get(servlet); DisplayNameImpl dispName = new DisplayNameImpl(); dispName.setDisplayName(portlet.getName() + " Wrapper"); dispName.setLocale(Locale.ENGLISH); DisplayNameSetImpl dispSet = new DisplayNameSetImpl(); dispSet.add(dispName); servletCtrl.setDisplayNames(dispSet); DescriptionImpl desc = new DescriptionImpl(); desc.setDescription("Automated generated Portlet Wrapper"); desc.setLocale(Locale.ENGLISH); DescriptionSetImpl descSet = new DescriptionSetImpl(); descSet.add(desc); servletCtrl.setDescriptions(descSet); ParameterSet parameters = servlet.getInitParameterSet(); ParameterSetCtrl parameterSetCtrl = (ParameterSetCtrl) controllerFactory .get(parameters); Parameter parameter1 = parameters.get("portlet-class"); if (parameter1 == null) { parameterSetCtrl.add("portlet-class", portlet.getClassName()); } else { ParameterCtrl parameterCtrl = (ParameterCtrl) controllerFactory.get(parameter1); parameterCtrl.setValue(portlet.getClassName()); } Parameter parameter2 = parameters.get("portlet-guid"); if (parameter2 == null) { parameterSetCtrl.add("portlet-guid", portlet.getId().toString()); } else { ParameterCtrl parameterCtrl = (ParameterCtrl) controllerFactory.get(parameter2); parameterCtrl.setValue(portlet.getId().toString()); } boolean found = false; Iterator mappings = servletMappings.iterator(); while (mappings.hasNext()) { ServletMappingImpl servletMapping = (ServletMappingImpl) mappings.next(); if (servletMapping.getServletName().equals(portlet.getName())) { found = true; servletMapping.setUrlPattern("/" + portlet.getName().replace(' ', '_') + "/*"); } } if (!found) { ServletMappingImpl servletMapping = new ServletMappingImpl(); servletMapping.setServletName(portlet.getName()); servletMapping.setUrlPattern("/" + portlet.getName().replace(' ', '_') + "/*"); servletMappings.add(servletMapping); } SecurityRoleRefSet servletSecurityRoleRefs = ((ServletDefinitionImpl) servlet) .getInitSecurityRoleRefSet(); SecurityRoleRefSetCtrl servletSecurityRoleRefSetCtrl = (SecurityRoleRefSetCtrl) controllerFactory .get(servletSecurityRoleRefs); SecurityRoleSet webAppSecurityRoles = webApp.getSecurityRoles(); SecurityRoleRefSet portletSecurityRoleRefs = portlet.getInitSecurityRoleRefSet(); Iterator p = portletSecurityRoleRefs.iterator(); while (p.hasNext()) { SecurityRoleRef portletSecurityRoleRef = (SecurityRoleRef) p.next(); if (portletSecurityRoleRef.getRoleLink() == null && webAppSecurityRoles.get(portletSecurityRoleRef.getRoleName()) == null) { logger.info("Note: The web application has no security role defined which matches the role name \"" + portletSecurityRoleRef.getRoleName() + "\" of the security-role-ref element defined for the wrapper-servlet with the name '" + portlet.getName() + "'."); break; } SecurityRoleRef servletSecurityRoleRef = servletSecurityRoleRefs .get(portletSecurityRoleRef.getRoleName()); if (null != servletSecurityRoleRef) { logger.info("Note: Replaced already existing element of type <security-role-ref> with value \"" + portletSecurityRoleRef.getRoleName() + "\" for subelement of type <role-name> for the wrapper-servlet with the name '" + portlet.getName() + "'."); servletSecurityRoleRefSetCtrl.remove(servletSecurityRoleRef); } servletSecurityRoleRefSetCtrl.add(portletSecurityRoleRef); } } */ /* * TODO is this necessary? TagDefinitionImpl portletTagLib = new * TagDefinitionImpl(); Collection taglibs = * webApp.getCastorTagDefinitions(); taglibs.add(portletTagLib); */ // Duplicate jar-file with replaced web.xml FileOutputStream fos = new FileOutputStream(tmp); JarOutputStream tempJar = new JarOutputStream(fos); byte[] buffer = new byte[1024]; int bytesRead; for (Enumeration entries = jar.entries(); entries.hasMoreElements();) { JarEntry entry = (JarEntry) entries.nextElement(); JarEntry newEntry = new JarEntry(entry.getName()); tempJar.putNextEntry(newEntry); if (entry.getName().equals(WEB_XML)) { // Swap web.xml /* log.debug("Swapping web.xml"); OutputFormat of = new OutputFormat(); of.setIndenting(true); of.setIndent(4); // 2-space indention of.setLineWidth(16384); of.setDoctype(Constants.WEB_PORTLET_PUBLIC_ID, Constants.WEB_PORTLET_DTD); XMLSerializer serializer = new XMLSerializer(tempJar, of); Marshaller marshaller = new Marshaller(serializer.asDocumentHandler()); marshaller.setMapping(sdmXml); marshaller.marshal(webApp); */ PortletAppDescriptorService portletAppDescriptorService = new StreamPortletAppDescriptorServiceImpl(appName, pis, null); File tmpf = File.createTempFile("infoglue-web-xml", null); WebAppDescriptorService webAppDescriptorService = new StreamWebAppDescriptorServiceImpl(appName, wis, new FileOutputStream(tmpf)); org.apache.pluto.driver.deploy.Deploy d = new org.apache.pluto.driver.deploy.Deploy(webAppDescriptorService, portletAppDescriptorService); d.updateDescriptors(); FileInputStream fis = new FileInputStream(tmpf); while ((bytesRead = fis.read(buffer)) != -1) { tempJar.write(buffer, 0, bytesRead); } tmpf.delete(); } else { InputStream entryStream = jar.getInputStream(entry); if(entryStream != null) { while ((bytesRead = entryStream.read(buffer)) != -1) { tempJar.write(buffer, 0, bytesRead); } } } } tempJar.flush(); tempJar.close(); fos.flush(); fos.close(); /* * String strTo = dirDelim + "WEB-INF" + dirDelim + "tld" + dirDelim + * "portlet.tld"; String strFrom = "webapps" + dirDelim + strTo; * * copy(strFrom, webAppsDir + webModule + strTo); */ } catch (Exception e) { log.error("Failed to prepare archive", e); throw new IOException(e.getMessage()); } return portletApp; } private static void copy(String from, String to) throws IOException { File f = new File(to); f.getParentFile().mkdirs(); InputStream fis = new FileInputStream(from); FileOutputStream fos = new FileOutputStream(f); copyStream(fis, fos); fos.close(); } private static int copyStream(InputStream is, OutputStream os) throws IOException { int total = 0; byte[] buffer = new byte[1024]; int length = 0; while ((length = is.read(buffer)) >= 0) { os.write(buffer, 0, length); total += length; } os.flush(); return total; } private static int expandArchive(File warFile, File destDir) throws IOException { int numEntries = 0; if (!destDir.exists()) { destDir.mkdirs(); } JarFile jarFile = new JarFile(warFile); Enumeration files = jarFile.entries(); while (files.hasMoreElements()) { JarEntry entry = (JarEntry) files.nextElement(); String fileName = entry.getName(); File file = new File(destDir, fileName); File dirF = new File(file.getParent()); dirF.mkdirs(); if (entry.isDirectory()) { file.mkdirs(); } else { InputStream fis = jarFile.getInputStream(entry); FileOutputStream fos = new FileOutputStream(file); copyStream(fis, fos); fos.close(); } numEntries++; } return numEntries; } public static void main(String[] args) { try { File file = new File("c:\\infoglueHome\\RssPortlet.war"); File tmp = new File("c:\\infoglueHome\\RssPortlet2.war"); prepareArchive(file, tmp, "test-portlet.war"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }