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                    return sb.toString();
169            }
170    
171            @Override
172            public String getExtraFiltersContent(double webXmlVersion, File srcFile)
173                    throws Exception {
174    
175                    StringBundler sb = new StringBundler(4);
176    
177                    String extraFiltersContent = super.getExtraFiltersContent(
178                            webXmlVersion, srcFile);
179    
180                    sb.append(extraFiltersContent);
181    
182                    // Ignore filters
183    
184                    sb.append(getIgnoreFiltersContent(srcFile));
185    
186                    // Speed filters
187    
188                    sb.append(getSpeedFiltersContent(srcFile));
189    
190                    // Servlet context include filters
191    
192                    sb.append(
193                            getServletContextIncludeFiltersContent(webXmlVersion, srcFile));
194    
195                    return sb.toString();
196            }
197    
198            @Override
199            public String getPluginType() {
200                    return Plugin.TYPE_PORTLET;
201            }
202    
203            public String getServletContent(File portletXML, File webXML)
204                    throws Exception {
205    
206                    StringBundler sb = new StringBundler();
207    
208                    // Add wrappers for portlets
209    
210                    Document doc = SAXReaderUtil.read(portletXML);
211    
212                    Element root = doc.getRootElement();
213    
214                    Iterator<Element> itr1 = root.elements("portlet").iterator();
215    
216                    while (itr1.hasNext()) {
217                            Element portlet = itr1.next();
218    
219                            String portletName = PortalUtil.getJsSafePortletId(
220                                    portlet.elementText("portlet-name"));
221                            String portletClass = portlet.elementText("portlet-class");
222    
223                            String servletName = portletName + " Servlet";
224    
225                            sb.append("<servlet>");
226                            sb.append("<servlet-name>");
227                            sb.append(servletName);
228                            sb.append("</servlet-name>");
229                            sb.append("<servlet-class>");
230                            sb.append("com.liferay.portal.kernel.servlet.PortletServlet");
231                            sb.append("</servlet-class>");
232                            sb.append("<init-param>");
233                            sb.append("<param-name>portlet-class</param-name>");
234                            sb.append("<param-value>");
235                            sb.append(portletClass);
236                            sb.append("</param-value>");
237                            sb.append("</init-param>");
238                            sb.append("<load-on-startup>1</load-on-startup>");
239                            sb.append("</servlet>");
240    
241                            sb.append("<servlet-mapping>");
242                            sb.append("<servlet-name>");
243                            sb.append(servletName);
244                            sb.append("</servlet-name>");
245                            sb.append("<url-pattern>/");
246                            sb.append(portletName);
247                            sb.append("/*</url-pattern>");
248                            sb.append("</servlet-mapping>");
249                    }
250    
251                    // Make sure there is a company id specified
252    
253                    doc = SAXReaderUtil.read(webXML);
254    
255                    root = doc.getRootElement();
256    
257                    // Remove deprecated references to SharedServletWrapper
258    
259                    itr1 = root.elements("servlet").iterator();
260    
261                    while (itr1.hasNext()) {
262                            Element servlet = itr1.next();
263    
264                            String icon = servlet.elementText("icon");
265                            String servletName = servlet.elementText("servlet-name");
266                            String displayName = servlet.elementText("display-name");
267                            String description = servlet.elementText("description");
268                            String servletClass = servlet.elementText("servlet-class");
269                            List<Element> initParams = servlet.elements("init-param");
270                            String loadOnStartup = servlet.elementText("load-on-startup");
271                            String runAs = servlet.elementText("run-as");
272                            List<Element> securityRoleRefs = servlet.elements(
273                                    "security-role-ref");
274    
275                            if ((servletClass != null) &&
276                                    (servletClass.equals(
277                                            "com.liferay.portal.servlet.SharedServletWrapper"))) {
278    
279                                    sb.append("<servlet>");
280    
281                                    if (icon != null) {
282                                            sb.append("<icon>");
283                                            sb.append(icon);
284                                            sb.append("</icon>");
285                                    }
286    
287                                    if (servletName != null) {
288                                            sb.append("<servlet-name>");
289                                            sb.append(servletName);
290                                            sb.append("</servlet-name>");
291                                    }
292    
293                                    if (displayName != null) {
294                                            sb.append("<display-name>");
295                                            sb.append(displayName);
296                                            sb.append("</display-name>");
297                                    }
298    
299                                    if (description != null) {
300                                            sb.append("<description>");
301                                            sb.append(description);
302                                            sb.append("</description>");
303                                    }
304    
305                                    Iterator<Element> itr2 = initParams.iterator();
306    
307                                    while (itr2.hasNext()) {
308                                            Element initParam = itr2.next();
309    
310                                            String paramName = initParam.elementText("param-name");
311                                            String paramValue = initParam.elementText("param-value");
312    
313                                            if ((paramName != null) &&
314                                                    (paramName.equals("servlet-class"))) {
315    
316                                                    sb.append("<servlet-class>");
317                                                    sb.append(paramValue);
318                                                    sb.append("</servlet-class>");
319                                            }
320                                    }
321    
322                                    itr2 = initParams.iterator();
323    
324                                    while (itr2.hasNext()) {
325                                            Element initParam = itr2.next();
326    
327                                            String paramName = initParam.elementText("param-name");
328                                            String paramValue = initParam.elementText("param-value");
329                                            String paramDesc = initParam.elementText("description");
330    
331                                            if ((paramName != null) &&
332                                                    (!paramName.equals("servlet-class"))) {
333    
334                                                    sb.append("<init-param>");
335                                                    sb.append("<param-name>");
336                                                    sb.append(paramName);
337                                                    sb.append("</param-name>");
338    
339                                                    if (paramValue != null) {
340                                                            sb.append("<param-value>");
341                                                            sb.append(paramValue);
342                                                            sb.append("</param-value>");
343                                                    }
344    
345                                                    if (paramDesc != null) {
346                                                            sb.append("<description>");
347                                                            sb.append(paramDesc);
348                                                            sb.append("</description>");
349                                                    }
350    
351                                                    sb.append("</init-param>");
352                                            }
353                                    }
354    
355                                    if (loadOnStartup != null) {
356                                            sb.append("<load-on-startup>");
357                                            sb.append(loadOnStartup);
358                                            sb.append("</load-on-startup>");
359                                    }
360    
361                                    if (runAs != null) {
362                                            sb.append("<run-as>");
363                                            sb.append(runAs);
364                                            sb.append("</run-as>");
365                                    }
366    
367                                    itr2 = securityRoleRefs.iterator();
368    
369                                    while (itr2.hasNext()) {
370                                            Element roleRef = itr2.next();
371    
372                                            String roleDesc = roleRef.elementText("description");
373                                            String roleName = roleRef.elementText("role-name");
374                                            String roleLink = roleRef.elementText("role-link");
375    
376                                            sb.append("<security-role-ref>");
377    
378                                            if (roleDesc != null) {
379                                                    sb.append("<description>");
380                                                    sb.append(roleDesc);
381                                                    sb.append("</description>");
382                                            }
383    
384                                            if (roleName != null) {
385                                                    sb.append("<role-name>");
386                                                    sb.append(roleName);
387                                                    sb.append("</role-name>");
388                                            }
389    
390                                            if (roleLink != null) {
391                                                    sb.append("<role-link>");
392                                                    sb.append(roleLink);
393                                                    sb.append("</role-link>");
394                                            }
395    
396                                            sb.append("</security-role-ref>");
397                                    }
398    
399                                    sb.append("</servlet>");
400                            }
401                    }
402    
403                    return sb.toString();
404            }
405    
406            public void setupJSF(File facesXML, File portletXML) throws Exception {
407                    _myFacesPortlet = false;
408                    _sunFacesPortlet = false;
409    
410                    if (!facesXML.exists()) {
411                            return;
412                    }
413    
414                    // portlet.xml
415    
416                    Document doc = SAXReaderUtil.read(portletXML, true);
417    
418                    Element root = doc.getRootElement();
419    
420                    List<Element> elements = root.elements("portlet");
421    
422                    Iterator<Element> itr = elements.iterator();
423    
424                    while (itr.hasNext()) {
425                            Element portlet = itr.next();
426    
427                            String portletClass = portlet.elementText("portlet-class");
428    
429                            if (portletClass.equals(JSF_MYFACES)) {
430                                    _myFacesPortlet = true;
431    
432                                    break;
433                            }
434                            else if (portletClass.equals(JSF_SUN)) {
435                                    _sunFacesPortlet = true;
436    
437                                    break;
438                            }
439                    }
440    
441                    // faces-config.xml
442    
443                    doc = SAXReaderUtil.read(facesXML, true);
444    
445                    root = doc.getRootElement();
446    
447                    Element factoryEl = root.element("factory");
448    
449                    Element renderKitFactoryEl = null;
450                    Element facesContextFactoryEl = null;
451    
452                    if (factoryEl == null) {
453                            factoryEl = root.addElement("factory");
454                    }
455    
456                    renderKitFactoryEl = factoryEl.element("render-kit-factory");
457                    facesContextFactoryEl = factoryEl.element("faces-context-factory");
458    
459                    if ((appServerType.equals("orion") && (_sunFacesPortlet) &&
460                             (renderKitFactoryEl == null))) {
461    
462                            renderKitFactoryEl = factoryEl.addElement("render-kit-factory");
463    
464                            renderKitFactoryEl.addText(LIFERAY_RENDER_KIT_FACTORY);
465                    }
466                    else if (_myFacesPortlet && (facesContextFactoryEl == null)) {
467                            facesContextFactoryEl = factoryEl.addElement(
468                                    "faces-context-factory");
469    
470                            facesContextFactoryEl.addText(MYFACES_CONTEXT_FACTORY);
471                    }
472    
473                    if (!appServerType.equals("orion") && (_sunFacesPortlet)) {
474                            factoryEl.detach();
475                    }
476    
477                    XMLMerger merger = new XMLMerger(new FacesXMLDescriptor());
478    
479                    DocumentImpl docImpl = (DocumentImpl)doc;
480    
481                    merger.organizeXML(docImpl.getWrappedDocument());
482    
483                    FileUtil.write(facesXML, doc.formattedString(), true);
484            }
485    
486            @Override
487            public void updateDeployDirectory(File srcFile) throws Exception {
488                    boolean customPortletXML = false;
489    
490                    try {
491                            customPortletXML = PrefsPropsUtil.getBoolean(
492                                    PropsKeys.AUTO_DEPLOY_CUSTOM_PORTLET_XML,
493                                    PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML);
494                    }
495                    catch (Exception e) {
496    
497                            // This will only happen when running the deploy tool in Ant in the
498                            // classical way where the WAR file is actually massaged and
499                            // packaged.
500    
501                            customPortletXML = PropsValues.AUTO_DEPLOY_CUSTOM_PORTLET_XML;
502                    }
503    
504                    customPortletXML = GetterUtil.getBoolean(
505                            System.getProperty("deployer.custom.portlet.xml"),
506                            customPortletXML);
507    
508                    if (!customPortletXML) {
509                            return;
510                    }
511    
512                    File portletXML = new File(
513                            srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD);
514    
515                    if (portletXML.exists()) {
516                            File portletCustomXML = new File(
517                                    srcFile + "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM);
518    
519                            if (portletCustomXML.exists()) {
520                                    portletCustomXML.delete();
521                            }
522    
523                            portletXML.renameTo(portletCustomXML);
524                    }
525            }
526    
527            public void updatePortletXML(File portletXML) throws Exception {
528                    if (!portletXML.exists()) {
529                            return;
530                    }
531    
532                    String content = FileUtil.read(portletXML);
533    
534                    content = StringUtil.replace(
535                            content, "com.liferay.util.bridges.jsp.JSPPortlet",
536                            MVCPortlet.class.getName());
537    
538                    FileUtil.write(portletXML, content);
539            }
540    
541            private boolean _myFacesPortlet;
542            private boolean _sunFacesPortlet;
543    
544    }