001 /** 002 * Copyright (c) 2000-2011 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 }