001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools.deploy;
016    
017    import com.liferay.portal.kernel.plugin.PluginPackage;
018    import com.liferay.portal.kernel.util.FileUtil;
019    import com.liferay.portal.kernel.util.GetterUtil;
020    import com.liferay.portal.kernel.util.PropsKeys;
021    import com.liferay.portal.kernel.util.ServerDetector;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Validator;
025    import com.liferay.portal.kernel.xml.Document;
026    import com.liferay.portal.kernel.xml.Element;
027    import com.liferay.portal.kernel.xml.SAXReaderUtil;
028    import com.liferay.portal.model.Plugin;
029    import com.liferay.portal.util.InitUtil;
030    import com.liferay.portal.util.Portal;
031    import com.liferay.portal.util.PortalUtil;
032    import com.liferay.portal.util.PrefsPropsUtil;
033    import com.liferay.portal.util.PropsValues;
034    import com.liferay.portal.xml.DocumentImpl;
035    import com.liferay.util.bridges.mvc.MVCPortlet;
036    import com.liferay.util.xml.XMLMerger;
037    import com.liferay.util.xml.descriptor.FacesXMLDescriptor;
038    
039    import java.io.File;
040    
041    import java.util.ArrayList;
042    import java.util.List;
043    
044    /**
045     * @author Brian Wing Shun Chan
046     * @author Brian Myunghun Kim
047     */
048    public class PortletDeployer extends BaseDeployer {
049    
050            public static final String JSF_MYFACES =
051                    "org.apache.myfaces.portlet.MyFacesGenericPortlet";
052    
053            public static final String JSF_STANDARD =
054                    "javax.portlet.faces.GenericFacesPortlet";
055    
056            public static final String JSF_SUN = "com.sun.faces.portlet.FacesPortlet";
057    
058            public static final String LIFERAY_RENDER_KIT_FACTORY =
059                    "com.liferay.util.jsf.sun.faces.renderkit.LiferayRenderKitFactoryImpl";
060    
061            public static final String MYFACES_CONTEXT_FACTORY =
062                    "com.liferay.util.bridges.jsf.myfaces.MyFacesContextFactoryImpl";
063    
064            public static void main(String[] args) {
065                    InitUtil.initWithSpring();
066    
067                    List<String> wars = new ArrayList<String>();
068                    List<String> jars = new ArrayList<String>();
069    
070                    for (String arg : args) {
071                            if (arg.endsWith(".war")) {
072                                    wars.add(arg);
073                            }
074                            else if (arg.endsWith(".jar")) {
075                                    jars.add(arg);
076                            }
077                    }
078    
079                    new PortletDeployer(wars, jars);
080            }
081    
082            public PortletDeployer() {
083            }
084    
085            public PortletDeployer(List<String> wars, List<String> jars) {
086                    super(wars, jars);
087            }
088    
089            @Override
090            public void checkArguments() {
091                    super.checkArguments();
092    
093                    if (Validator.isNull(portletTaglibDTD)) {
094                            throw new IllegalArgumentException(
095                                    "The system property deployer.portlet.taglib.dtd is not set");
096                    }
097            }
098    
099            @Override
100            public void copyXmls(
101                            File srcFile, String displayName, PluginPackage pluginPackage)
102                    throws Exception {
103    
104                    super.copyXmls(srcFile, displayName, pluginPackage);
105    
106                    copyTomcatContextXml(srcFile);
107    
108                    copyDependencyXml(
109                            "_servlet_context_include.jsp", srcFile + "/WEB-INF/jsp");
110            }
111    
112            @Override
113            public String getExtraContent(
114                            double webXmlVersion, File srcFile, String displayName)
115                    throws Exception {
116    
117                    StringBundler sb = new StringBundler();
118    
119                    if (ServerDetector.isWebSphere()) {
120                            sb.append("<context-param>");
121                            sb.append("<param-name>");
122                            sb.append("com.ibm.websphere.portletcontainer.");
123                            sb.append("PortletDeploymentEnabled");
124                            sb.append("</param-name>");
125                            sb.append("<param-value>false</param-value>");
126                            sb.append("</context-param>");
127                    }
128    
129                    File facesXML = new File(srcFile + "/WEB-INF/faces-config.xml");
130                    File portletXML = new File(
131                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
132                    File webXML = new File(srcFile + "/WEB-INF/web.xml");
133    
134                    updatePortletXML(portletXML);
135    
136                    sb.append(getServletContent(portletXML, webXML));
137    
138                    setupJSF(facesXML, portletXML);
139    
140                    if (_sunFacesPortlet) {
141    
142                            // LiferayConfigureListener
143    
144                            sb.append("<listener>");
145                            sb.append("<listener-class>");
146                            sb.append("com.liferay.util.bridges.jsf.sun.");
147                            sb.append("LiferayConfigureListener");
148                            sb.append("</listener-class>");
149                            sb.append("</listener>");
150                    }
151    
152                    String extraContent = super.getExtraContent(
153                            webXmlVersion, srcFile, displayName);
154    
155                    sb.append(extraContent);
156    
157                    return sb.toString();
158            }
159    
160            @Override
161            public String getExtraFiltersContent(double webXmlVersion, File srcFile)
162                    throws Exception {
163    
164                    StringBundler sb = new StringBundler(4);
165    
166                    String extraFiltersContent = super.getExtraFiltersContent(
167                            webXmlVersion, srcFile);
168    
169                    sb.append(extraFiltersContent);
170    
171                    // Ignore filters
172    
173                    sb.append(getIgnoreFiltersContent(srcFile));
174    
175                    // Speed filters
176    
177                    sb.append(getSpeedFiltersContent(srcFile));
178    
179                    // Servlet context include filters
180    
181                    sb.append(
182                            getServletContextIncludeFiltersContent(webXmlVersion, srcFile));
183    
184                    return sb.toString();
185            }
186    
187            @Override
188            public String getPluginType() {
189                    return Plugin.TYPE_PORTLET;
190            }
191    
192            public String getServletContent(File portletXML, File webXML)
193                    throws Exception {
194    
195                    StringBundler sb = new StringBundler();
196    
197                    Document document = SAXReaderUtil.read(portletXML);
198    
199                    Element rootElement = document.getRootElement();
200    
201                    List<Element> portletElements = rootElement.elements("portlet");
202    
203                    for (Element portletElement : portletElements) {
204                            String portletName = PortalUtil.getJsSafePortletId(
205                                    portletElement.elementText("portlet-name"));
206                            String portletClass = portletElement.elementText("portlet-class");
207    
208                            String servletName = portletName + " Servlet";
209    
210                            sb.append("<servlet>");
211                            sb.append("<servlet-name>");
212                            sb.append(servletName);
213                            sb.append("</servlet-name>");
214                            sb.append("<servlet-class>");
215                            sb.append("com.liferay.portal.kernel.servlet.PortletServlet");
216                            sb.append("</servlet-class>");
217                            sb.append("<init-param>");
218                            sb.append("<param-name>portlet-class</param-name>");
219                            sb.append("<param-value>");
220                            sb.append(portletClass);
221                            sb.append("</param-value>");
222                            sb.append("</init-param>");
223                            sb.append("<load-on-startup>1</load-on-startup>");
224                            sb.append("</servlet>");
225    
226                            sb.append("<servlet-mapping>");
227                            sb.append("<servlet-name>");
228                            sb.append(servletName);
229                            sb.append("</servlet-name>");
230                            sb.append("<url-pattern>/");
231                            sb.append(portletName);
232                            sb.append("/*</url-pattern>");
233                            sb.append("</servlet-mapping>");
234                    }
235    
236                    return sb.toString();
237            }
238    
239            public void setupJSF(File facesXML, File portletXML) throws Exception {
240                    _myFacesPortlet = false;
241                    _sunFacesPortlet = false;
242    
243                    if (!facesXML.exists()) {
244                            return;
245                    }
246    
247                    // portlet.xml
248    
249                    Document document = SAXReaderUtil.read(portletXML, true);
250    
251                    Element rootElement = document.getRootElement();
252    
253                    List<Element> portletElements = rootElement.elements("portlet");
254    
255                    for (Element portletElement : portletElements) {
256                            String portletClass = portletElement.elementText("portlet-class");
257    
258                            if (portletClass.equals(JSF_MYFACES)) {
259                                    _myFacesPortlet = true;
260    
261                                    break;
262                            }
263                            else if (portletClass.equals(JSF_SUN)) {
264                                    _sunFacesPortlet = true;
265    
266                                    break;
267                            }
268                    }
269    
270                    // faces-config.xml
271    
272                    document = SAXReaderUtil.read(facesXML, true);
273    
274                    rootElement = document.getRootElement();
275    
276                    Element factoryElement = rootElement.element("factory");
277    
278                    Element renderKitFactoryElement = null;
279                    Element facesContextFactoryElement = null;
280    
281                    if (factoryElement == null) {
282                            factoryElement = rootElement.addElement("factory");
283                    }
284    
285                    renderKitFactoryElement = factoryElement.element("render-kit-factory");
286                    facesContextFactoryElement = factoryElement.element(
287                            "faces-context-factory");
288    
289                    if (appServerType.equals("orion") && _sunFacesPortlet &&
290                            (renderKitFactoryElement == null)) {
291    
292                            renderKitFactoryElement = factoryElement.addElement(
293                                    "render-kit-factory");
294    
295                            renderKitFactoryElement.addText(LIFERAY_RENDER_KIT_FACTORY);
296                    }
297                    else if (_myFacesPortlet && (facesContextFactoryElement == null)) {
298                            facesContextFactoryElement = factoryElement.addElement(
299                                    "faces-context-factory");
300    
301                            facesContextFactoryElement.addText(MYFACES_CONTEXT_FACTORY);
302                    }
303    
304                    if (!appServerType.equals("orion") && _sunFacesPortlet) {
305                            factoryElement.detach();
306                    }
307    
308                    XMLMerger xmlMerger = new XMLMerger(new FacesXMLDescriptor());
309    
310                    DocumentImpl documentImpl = (DocumentImpl)document;
311    
312                    xmlMerger.organizeXML(documentImpl.getWrappedDocument());
313    
314                    FileUtil.write(facesXML, document.formattedString(), true);
315            }
316    
317            @Override
318            public void updateDeployDirectory(File srcFile) throws Exception {
319                    boolean customPortletXML = false;
320    
321                    try {
322                            customPortletXML = PrefsPropsUtil.getBoolean(
323                                    PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML,
324                                    PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML);
325                    }
326                    catch (Exception e) {
327    
328                            // This will only happen when running the deploy tool in Ant in the
329                            // classical way where the WAR file is actually massaged and
330                            // packaged.
331    
332                            customPortletXML = PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML;
333                    }
334    
335                    customPortletXML = GetterUtil.getBoolean(
336                            System.getProperty("deployer.custom.portlet.xml"),
337                            customPortletXML);
338    
339                    if (!customPortletXML) {
340                            return;
341                    }
342    
343                    File portletXML = new File(
344                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
345    
346                    if (portletXML.exists()) {
347                            File portletCustomXML = new File(
348                                    srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM);
349    
350                            if (portletCustomXML.exists()) {
351                                    portletCustomXML.delete();
352                            }
353    
354                            portletXML.renameTo(portletCustomXML);
355                    }
356            }
357    
358            public void updatePortletXML(File portletXML) throws Exception {
359                    if (!portletXML.exists()) {
360                            return;
361                    }
362    
363                    String content = FileUtil.read(portletXML);
364    
365                    content = StringUtil.replace(
366                            content, "com.liferay.util.bridges.jsp.JSPPortlet",
367                            MVCPortlet.class.getName());
368    
369                    FileUtil.write(portletXML, content);
370            }
371    
372            private boolean _myFacesPortlet;
373            private boolean _sunFacesPortlet;
374    
375    }