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.Iterator;
043    import java.util.List;
044    
045    /**
046     * @author Brian Wing Shun Chan
047     * @author Brian Myunghun Kim
048     */
049    public class PortletDeployer extends BaseDeployer {
050    
051            public static final String JSF_MYFACES =
052                    "org.apache.myfaces.portlet.MyFacesGenericPortlet";
053    
054            public static final String JSF_STANDARD =
055                    "javax.portlet.faces.GenericFacesPortlet";
056    
057            public static final String JSF_SUN = "com.sun.faces.portlet.FacesPortlet";
058    
059            public static final String LIFERAY_RENDER_KIT_FACTORY =
060                    "com.liferay.util.jsf.sun.faces.renderkit.LiferayRenderKitFactoryImpl";
061    
062            public static final String MYFACES_CONTEXT_FACTORY =
063                    "com.liferay.util.bridges.jsf.myfaces.MyFacesContextFactoryImpl";
064    
065            public static void main(String[] args) {
066                    InitUtil.initWithSpring();
067    
068                    List<String> wars = new ArrayList<String>();
069                    List<String> jars = new ArrayList<String>();
070    
071                    for (String arg : args) {
072                            if (arg.endsWith(".war")) {
073                                    wars.add(arg);
074                            }
075                            else if (arg.endsWith(".jar")) {
076                                    jars.add(arg);
077                            }
078                    }
079    
080                    new PortletDeployer(wars, jars);
081            }
082    
083            public PortletDeployer() {
084            }
085    
086            public PortletDeployer(List<String> wars, List<String> jars) {
087                    super(wars, jars);
088            }
089    
090            @Override
091            public void checkArguments() {
092                    super.checkArguments();
093    
094                    if (Validator.isNull(portletTaglibDTD)) {
095                            throw new IllegalArgumentException(
096                                    "The system property deployer.portlet.taglib.dtd is not set");
097                    }
098            }
099    
100            @Override
101            public void copyXmls(
102                            File srcFile, String displayName, PluginPackage pluginPackage)
103                    throws Exception {
104    
105                    super.copyXmls(srcFile, displayName, pluginPackage);
106    
107                    if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
108                            copyDependencyXml("context.xml", srcFile + "/META-INF");
109                    }
110    
111                    copyDependencyXml(
112                            "_servlet_context_include.jsp", srcFile + "/WEB-INF/jsp");
113            }
114    
115            @Override
116            public String getExtraContent(
117                            double webXmlVersion, File srcFile, String displayName)
118                    throws Exception {
119    
120                    StringBundler sb = new StringBundler();
121    
122                    String extraContent = super.getExtraContent(
123                            webXmlVersion, srcFile, displayName);
124    
125                    sb.append(extraContent);
126    
127                    if (ServerDetector.isWebSphere()) {
128                            sb.append("<context-param>");
129                            sb.append("<param-name>");
130                            sb.append("com.ibm.websphere.portletcontainer.");
131                            sb.append("PortletDeploymentEnabled");
132                            sb.append("</param-name>");
133                            sb.append("<param-value>false</param-value>");
134                            sb.append("</context-param>");
135                    }
136    
137                    File facesXML = new File(srcFile + "/WEB-INF/faces-config.xml");
138                    File portletXML = new File(
139                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
140                    File webXML = new File(srcFile + "/WEB-INF/web.xml");
141    
142                    updatePortletXML(portletXML);
143    
144                    sb.append(getServletContent(portletXML, webXML));
145    
146                    setupJSF(facesXML, portletXML);
147    
148                    if (_sunFacesPortlet) {
149    
150                            // LiferayConfigureListener
151    
152                            sb.append("<listener>");
153                            sb.append("<listener-class>");
154                            sb.append("com.liferay.util.bridges.jsf.sun.");
155                            sb.append("LiferayConfigureListener");
156                            sb.append("</listener-class>");
157                            sb.append("</listener>");
158                    }
159    
160                    // PortletContextListener
161    
162                    sb.append("<listener>");
163                    sb.append("<listener-class>");
164                    sb.append("com.liferay.portal.kernel.servlet.PortletContextListener");
165                    sb.append("</listener-class>");
166                    sb.append("</listener>");
167    
168                    // Ignore filters
169    
170                    sb.append(getIgnoreFiltersContent(srcFile));
171    
172                    // Speed filters
173    
174                    sb.append(getSpeedFiltersContent(srcFile));
175    
176                    // Servlet context include filters
177    
178                    sb.append(
179                            getServletContextIncludeFiltersContent(webXmlVersion, srcFile));
180    
181                    return sb.toString();
182            }
183    
184            @Override
185            public String getPluginType() {
186                    return Plugin.TYPE_PORTLET;
187            }
188    
189            public String getServletContent(File portletXML, File webXML)
190                    throws Exception {
191    
192                    StringBundler sb = new StringBundler();
193    
194                    // Add wrappers for portlets
195    
196                    Document doc = SAXReaderUtil.read(portletXML);
197    
198                    Element root = doc.getRootElement();
199    
200                    Iterator<Element> itr1 = root.elements("portlet").iterator();
201    
202                    while (itr1.hasNext()) {
203                            Element portlet = itr1.next();
204    
205                            String portletName = PortalUtil.getJsSafePortletId(
206                                    portlet.elementText("portlet-name"));
207                            String portletClass = portlet.elementText("portlet-class");
208    
209                            String servletName = portletName + " Servlet";
210    
211                            sb.append("<servlet>");
212                            sb.append("<servlet-name>");
213                            sb.append(servletName);
214                            sb.append("</servlet-name>");
215                            sb.append("<servlet-class>");
216                            sb.append("com.liferay.portal.kernel.servlet.PortletServlet");
217                            sb.append("</servlet-class>");
218                            sb.append("<init-param>");
219                            sb.append("<param-name>portlet-class</param-name>");
220                            sb.append("<param-value>");
221                            sb.append(portletClass);
222                            sb.append("</param-value>");
223                            sb.append("</init-param>");
224                            sb.append("<load-on-startup>1</load-on-startup>");
225                            sb.append("</servlet>");
226    
227                            sb.append("<servlet-mapping>");
228                            sb.append("<servlet-name>");
229                            sb.append(servletName);
230                            sb.append("</servlet-name>");
231                            sb.append("<url-pattern>/");
232                            sb.append(portletName);
233                            sb.append("/*</url-pattern>");
234                            sb.append("</servlet-mapping>");
235                    }
236    
237                    // Make sure there is a company id specified
238    
239                    doc = SAXReaderUtil.read(webXML);
240    
241                    root = doc.getRootElement();
242    
243                    // Remove deprecated references to SharedServletWrapper
244    
245                    itr1 = root.elements("servlet").iterator();
246    
247                    while (itr1.hasNext()) {
248                            Element servlet = itr1.next();
249    
250                            String icon = servlet.elementText("icon");
251                            String servletName = servlet.elementText("servlet-name");
252                            String displayName = servlet.elementText("display-name");
253                            String description = servlet.elementText("description");
254                            String servletClass = servlet.elementText("servlet-class");
255                            List<Element> initParams = servlet.elements("init-param");
256                            String loadOnStartup = servlet.elementText("load-on-startup");
257                            String runAs = servlet.elementText("run-as");
258                            List<Element> securityRoleRefs = servlet.elements(
259                                    "security-role-ref");
260    
261                            if ((servletClass != null) &&
262                                    (servletClass.equals(
263                                            "com.liferay.portal.servlet.SharedServletWrapper"))) {
264    
265                                    sb.append("<servlet>");
266    
267                                    if (icon != null) {
268                                            sb.append("<icon>");
269                                            sb.append(icon);
270                                            sb.append("</icon>");
271                                    }
272    
273                                    if (servletName != null) {
274                                            sb.append("<servlet-name>");
275                                            sb.append(servletName);
276                                            sb.append("</servlet-name>");
277                                    }
278    
279                                    if (displayName != null) {
280                                            sb.append("<display-name>");
281                                            sb.append(displayName);
282                                            sb.append("</display-name>");
283                                    }
284    
285                                    if (description != null) {
286                                            sb.append("<description>");
287                                            sb.append(description);
288                                            sb.append("</description>");
289                                    }
290    
291                                    Iterator<Element> itr2 = initParams.iterator();
292    
293                                    while (itr2.hasNext()) {
294                                            Element initParam = itr2.next();
295    
296                                            String paramName = initParam.elementText("param-name");
297                                            String paramValue = initParam.elementText("param-value");
298    
299                                            if ((paramName != null) &&
300                                                    (paramName.equals("servlet-class"))) {
301    
302                                                    sb.append("<servlet-class>");
303                                                    sb.append(paramValue);
304                                                    sb.append("</servlet-class>");
305                                            }
306                                    }
307    
308                                    itr2 = initParams.iterator();
309    
310                                    while (itr2.hasNext()) {
311                                            Element initParam = itr2.next();
312    
313                                            String paramName = initParam.elementText("param-name");
314                                            String paramValue = initParam.elementText("param-value");
315                                            String paramDesc = initParam.elementText("description");
316    
317                                            if ((paramName != null) &&
318                                                    (!paramName.equals("servlet-class"))) {
319    
320                                                    sb.append("<init-param>");
321                                                    sb.append("<param-name>");
322                                                    sb.append(paramName);
323                                                    sb.append("</param-name>");
324    
325                                                    if (paramValue != null) {
326                                                            sb.append("<param-value>");
327                                                            sb.append(paramValue);
328                                                            sb.append("</param-value>");
329                                                    }
330    
331                                                    if (paramDesc != null) {
332                                                            sb.append("<description>");
333                                                            sb.append(paramDesc);
334                                                            sb.append("</description>");
335                                                    }
336    
337                                                    sb.append("</init-param>");
338                                            }
339                                    }
340    
341                                    if (loadOnStartup != null) {
342                                            sb.append("<load-on-startup>");
343                                            sb.append(loadOnStartup);
344                                            sb.append("</load-on-startup>");
345                                    }
346    
347                                    if (runAs != null) {
348                                            sb.append("<run-as>");
349                                            sb.append(runAs);
350                                            sb.append("</run-as>");
351                                    }
352    
353                                    itr2 = securityRoleRefs.iterator();
354    
355                                    while (itr2.hasNext()) {
356                                            Element roleRef = itr2.next();
357    
358                                            String roleDesc = roleRef.elementText("description");
359                                            String roleName = roleRef.elementText("role-name");
360                                            String roleLink = roleRef.elementText("role-link");
361    
362                                            sb.append("<security-role-ref>");
363    
364                                            if (roleDesc != null) {
365                                                    sb.append("<description>");
366                                                    sb.append(roleDesc);
367                                                    sb.append("</description>");
368                                            }
369    
370                                            if (roleName != null) {
371                                                    sb.append("<role-name>");
372                                                    sb.append(roleName);
373                                                    sb.append("</role-name>");
374                                            }
375    
376                                            if (roleLink != null) {
377                                                    sb.append("<role-link>");
378                                                    sb.append(roleLink);
379                                                    sb.append("</role-link>");
380                                            }
381    
382                                            sb.append("</security-role-ref>");
383                                    }
384    
385                                    sb.append("</servlet>");
386                            }
387                    }
388    
389                    return sb.toString();
390            }
391    
392            public void setupJSF(File facesXML, File portletXML) throws Exception {
393                    _myFacesPortlet = false;
394                    _sunFacesPortlet = false;
395    
396                    if (!facesXML.exists()) {
397                            return;
398                    }
399    
400                    // portlet.xml
401    
402                    Document doc = SAXReaderUtil.read(portletXML, true);
403    
404                    Element root = doc.getRootElement();
405    
406                    List<Element> elements = root.elements("portlet");
407    
408                    Iterator<Element> itr = elements.iterator();
409    
410                    while (itr.hasNext()) {
411                            Element portlet = itr.next();
412    
413                            String portletClass = portlet.elementText("portlet-class");
414    
415                            if (portletClass.equals(JSF_MYFACES)) {
416                                    _myFacesPortlet = true;
417    
418                                    break;
419                            }
420                            else if (portletClass.equals(JSF_SUN)) {
421                                    _sunFacesPortlet = true;
422    
423                                    break;
424                            }
425                    }
426    
427                    // faces-config.xml
428    
429                    doc = SAXReaderUtil.read(facesXML, true);
430    
431                    root = doc.getRootElement();
432    
433                    Element factoryEl = root.element("factory");
434    
435                    Element renderKitFactoryEl = null;
436                    Element facesContextFactoryEl = null;
437    
438                    if (factoryEl == null) {
439                            factoryEl = root.addElement("factory");
440                    }
441    
442                    renderKitFactoryEl = factoryEl.element("render-kit-factory");
443                    facesContextFactoryEl = factoryEl.element("faces-context-factory");
444    
445                    if ((appServerType.equals("orion") && (_sunFacesPortlet) &&
446                             (renderKitFactoryEl == null))) {
447    
448                            renderKitFactoryEl = factoryEl.addElement("render-kit-factory");
449    
450                            renderKitFactoryEl.addText(LIFERAY_RENDER_KIT_FACTORY);
451                    }
452                    else if (_myFacesPortlet && (facesContextFactoryEl == null)) {
453                            facesContextFactoryEl = factoryEl.addElement(
454                                    "faces-context-factory");
455    
456                            facesContextFactoryEl.addText(MYFACES_CONTEXT_FACTORY);
457                    }
458    
459                    if (!appServerType.equals("orion") && (_sunFacesPortlet)) {
460                            factoryEl.detach();
461                    }
462    
463                    XMLMerger merger = new XMLMerger(new FacesXMLDescriptor());
464    
465                    DocumentImpl docImpl = (DocumentImpl)doc;
466    
467                    merger.organizeXML(docImpl.getWrappedDocument());
468    
469                    FileUtil.write(facesXML, doc.formattedString(), true);
470            }
471    
472            @Override
473            public void updateDeployDirectory(File srcFile) throws Exception {
474                    boolean customPortletXML = false;
475    
476                    try {
477                            customPortletXML = PrefsPropsUtil.getBoolean(
478                                    PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML,
479                                    PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML);
480                    }
481                    catch (Exception e) {
482    
483                            // This will only happen when running the deploy tool in Ant in the
484                            // classical way where the WAR file is actually massaged and
485                            // packaged.
486    
487                            customPortletXML = PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML;
488                    }
489    
490                    customPortletXML = GetterUtil.getBoolean(
491                            System.getProperty("deployer.custom.portlet.xml"),
492                            customPortletXML);
493    
494                    if (!customPortletXML) {
495                            return;
496                    }
497    
498                    File portletXML = new File(
499                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
500    
501                    if (portletXML.exists()) {
502                            File portletCustomXML = new File(
503                                    srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM);
504    
505                            if (portletCustomXML.exists()) {
506                                    portletCustomXML.delete();
507                            }
508    
509                            portletXML.renameTo(portletCustomXML);
510                    }
511            }
512    
513            public void updatePortletXML(File portletXML) throws Exception {
514                    if (!portletXML.exists()) {
515                            return;
516                    }
517    
518                    String content = FileUtil.read(portletXML);
519    
520                    content = StringUtil.replace(
521                            content, "com.liferay.util.bridges.jsp.JSPPortlet",
522                            MVCPortlet.class.getName());
523    
524                    FileUtil.write(portletXML, content);
525            }
526    
527            private boolean _myFacesPortlet;
528            private boolean _sunFacesPortlet;
529    
530    }