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 }