1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.tools;
24  
25  import com.liferay.portal.deploy.DeployUtil;
26  import com.liferay.portal.kernel.deploy.auto.AutoDeployException;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.plugin.PluginPackage;
30  import com.liferay.portal.kernel.util.FileUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.HttpUtil;
33  import com.liferay.portal.kernel.util.PropertiesUtil;
34  import com.liferay.portal.kernel.util.ServerDetector;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.StringUtil;
37  import com.liferay.portal.kernel.util.Time;
38  import com.liferay.portal.kernel.util.Validator;
39  import com.liferay.portal.kernel.xml.Document;
40  import com.liferay.portal.kernel.xml.Element;
41  import com.liferay.portal.kernel.xml.SAXReaderUtil;
42  import com.liferay.portal.plugin.PluginPackageUtil;
43  import com.liferay.portal.util.InitUtil;
44  import com.liferay.portal.util.PortalUtil;
45  import com.liferay.portal.util.PrefsPropsUtil;
46  import com.liferay.portal.util.PropsKeys;
47  import com.liferay.portal.util.PropsUtil;
48  import com.liferay.portal.util.PropsValues;
49  import com.liferay.util.License;
50  import com.liferay.util.SystemProperties;
51  import com.liferay.util.ant.CopyTask;
52  import com.liferay.util.ant.DeleteTask;
53  import com.liferay.util.ant.ExpandTask;
54  import com.liferay.util.ant.UpToDateTask;
55  import com.liferay.util.ant.WarTask;
56  import com.liferay.util.xml.XMLFormatter;
57  
58  import com.sun.portal.portletcontainer.warupdater.PortletWarUpdater;
59  
60  import java.io.File;
61  import java.io.FileInputStream;
62  import java.io.IOException;
63  import java.io.InputStream;
64  
65  import java.util.ArrayList;
66  import java.util.List;
67  import java.util.Map;
68  import java.util.Properties;
69  import java.util.zip.ZipEntry;
70  import java.util.zip.ZipFile;
71  
72  import org.apache.oro.io.GlobFilenameFilter;
73  
74  /**
75   * <a href="BaseDeployer.java.html"><b><i>View Source</i></b></a>
76   *
77   * @author Brian Wing Shun Chan
78   *
79   */
80  public class BaseDeployer {
81  
82      public static final String DEPLOY_TO_PREFIX = "DEPLOY_TO__";
83  
84      public static void main(String[] args) {
85          InitUtil.initWithSpring();
86  
87          List<String> wars = new ArrayList<String>();
88          List<String> jars = new ArrayList<String>();
89  
90          for (String arg : args) {
91              String fileName = arg.toLowerCase();
92  
93              if (fileName.endsWith(".war")) {
94                  wars.add(arg);
95              }
96              else if (fileName.endsWith(".jar")) {
97                  jars.add(arg);
98              }
99          }
100 
101         new BaseDeployer(wars, jars);
102     }
103 
104     protected BaseDeployer() {
105     }
106 
107     protected BaseDeployer(List<String> wars, List<String> jars) {
108         baseDir = System.getProperty("deployer.base.dir");
109         destDir = System.getProperty("deployer.dest.dir");
110         appServerType = System.getProperty("deployer.app.server.type");
111         portletTaglibDTD = System.getProperty("deployer.portlet.taglib.dtd");
112         portletExtTaglibDTD = System.getProperty(
113             "deployer.portlet.ext.taglib.dtd");
114         securityTaglibDTD = System.getProperty("deployer.security.taglib.dtd");
115         themeTaglibDTD = System.getProperty("deployer.theme.taglib.dtd");
116         uiTaglibDTD = System.getProperty("deployer.ui.taglib.dtd");
117         utilTaglibDTD = System.getProperty("deployer.util.taglib.dtd");
118         unpackWar = GetterUtil.getBoolean(
119             System.getProperty("deployer.unpack.war"), true);
120         filePattern = System.getProperty("deployer.file.pattern");
121         jbossPrefix = GetterUtil.getString(
122             System.getProperty("deployer.jboss.prefix"));
123         tomcatLibDir = System.getProperty("deployer.tomcat.lib.dir");
124         this.wars = wars;
125         this.jars = jars;
126 
127         checkArguments();
128 
129         try {
130             deploy();
131         }
132         catch (Exception e) {
133             e.printStackTrace();
134         }
135     }
136 
137     protected void checkArguments() {
138         if (Validator.isNull(baseDir)) {
139             throw new IllegalArgumentException(
140                 "The system property deployer.base.dir is not set");
141         }
142 
143         if (Validator.isNull(destDir)) {
144             throw new IllegalArgumentException(
145                 "The system property deployer.dest.dir is not set");
146         }
147 
148         if (Validator.isNull(appServerType)) {
149             throw new IllegalArgumentException(
150                 "The system property deployer.app.server.type is not set");
151         }
152 
153         if (!appServerType.startsWith(ServerDetector.GERONIMO_ID) &&
154             !appServerType.startsWith(ServerDetector.GLASSFISH_ID) &&
155             !appServerType.startsWith(ServerDetector.JBOSS_ID) &&
156             !appServerType.startsWith(ServerDetector.JONAS_ID) &&
157             !appServerType.equals(ServerDetector.JETTY_ID) &&
158             !appServerType.equals(ServerDetector.OC4J_ID) &&
159             !appServerType.equals(ServerDetector.ORION_ID) &&
160             !appServerType.equals(ServerDetector.PRAMATI_ID) &&
161             !appServerType.equals(ServerDetector.RESIN_ID) &&
162             !appServerType.equals(ServerDetector.TOMCAT_ID) &&
163             !appServerType.equals(ServerDetector.WEBLOGIC_ID) &&
164             !appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
165 
166             throw new IllegalArgumentException(
167                 appServerType + " is not a valid application server type");
168         }
169 
170         if (appServerType.startsWith(ServerDetector.GLASSFISH_ID) ||
171             appServerType.equals(ServerDetector.PRAMATI_ID) ||
172             appServerType.equals(ServerDetector.WEBLOGIC_ID)) {
173 
174             unpackWar = false;
175         }
176 
177         if (Validator.isNotNull(jbossPrefix) &&
178             !Validator.isNumber(jbossPrefix)) {
179 
180             jbossPrefix = "1";
181         }
182     }
183 
184     protected void copyDependencyXml(String fileName, String targetDir)
185         throws Exception {
186 
187         copyDependencyXml(fileName, targetDir, null);
188     }
189 
190     protected void copyDependencyXml(
191             String fileName, String targetDir, Map<String, String> filterMap)
192         throws Exception {
193 
194         copyDependencyXml(fileName, targetDir, filterMap, false);
195     }
196 
197     protected void copyDependencyXml(
198             String fileName, String targetDir, Map<String, String> filterMap,
199             boolean overwrite)
200         throws Exception {
201 
202         File file = new File(DeployUtil.getResourcePath(fileName));
203         File targetFile = new File(targetDir + "/" + fileName);
204 
205         if (!targetFile.exists()) {
206             CopyTask.copyFile(
207                 file, new File(targetDir), filterMap, overwrite, true);
208         }
209     }
210 
211     protected void copyJars(File srcFile, PluginPackage pluginPackage)
212         throws Exception {
213 
214         for (int i = 0; i < jars.size(); i++) {
215             String jarFullName = jars.get(i);
216             String jarName = jarFullName.substring(
217                 jarFullName.lastIndexOf("/") + 1, jarFullName.length());
218 
219             if ((!appServerType.equals(ServerDetector.TOMCAT_ID)) ||
220                 (appServerType.equals(ServerDetector.TOMCAT_ID) &&
221                     !jarFullName.equals("util-java.jar"))) {
222 
223                 FileUtil.copyFile(
224                     jarFullName, srcFile + "/WEB-INF/lib/" + jarName, true);
225             }
226         }
227 
228         FileUtil.delete(srcFile + "/WEB-INF/lib/util-jsf.jar");
229     }
230 
231     protected void copyPortalDependencies(File srcFile) throws Exception {
232         Properties properties = getPluginPackageProperties(srcFile);
233 
234         if (properties == null) {
235             return;
236         }
237 
238         // jars
239 
240         String[] portalJars = StringUtil.split(
241             properties.getProperty(
242                 "portal-dependency-jars",
243                 properties.getProperty("portal.dependency.jars")));
244 
245         for (int i = 0; i < portalJars.length; i++) {
246             String portalJar = portalJars[i].trim();
247 
248             if (_log.isDebugEnabled()) {
249                 _log.debug("Copy portal JAR " + portalJar);
250             }
251 
252             try {
253                 String portalJarPath = PortalUtil.getPortalLibDir() + portalJar;
254 
255                 FileUtil.copyFile(
256                     portalJarPath, srcFile + "/WEB-INF/lib/" + portalJar, true);
257             }
258             catch (Exception e) {
259                 _log.error("Unable to copy portal JAR " + portalJar, e);
260             }
261         }
262 
263         // tlds
264 
265         String[] portalTlds = StringUtil.split(
266             properties.getProperty(
267                 "portal-dependency-tlds",
268                 properties.getProperty("portal.dependency.tlds")));
269 
270         for (int i = 0; i < portalTlds.length; i++) {
271             String portalTld = portalTlds[i].trim();
272 
273             if (_log.isDebugEnabled()) {
274                 _log.debug("Copy portal TLD " + portalTld);
275             }
276 
277             try {
278                 String portalTldPath = DeployUtil.getResourcePath(portalTld);
279 
280                 FileUtil.copyFile(
281                     portalTldPath, srcFile + "/WEB-INF/tld/" + portalTld, true);
282             }
283             catch (Exception e) {
284                 _log.error("Unable to copy portal TLD " + portalTld, e);
285             }
286         }
287 
288         // commons-logging*.jar
289 
290         File pluginLibDir = new File(srcFile + "/WEB-INF/lib/");
291 
292         String[] commonsLoggingJars = pluginLibDir.list(
293             new GlobFilenameFilter("commons-logging*.jar"));
294 
295         if ((commonsLoggingJars == null) || (commonsLoggingJars.length == 0)) {
296             String portalJarPath =
297                 PortalUtil.getPortalLibDir() + "commons-logging.jar";
298 
299             FileUtil.copyFile(
300                 portalJarPath, srcFile + "/WEB-INF/lib/commons-logging.jar",
301                 true);
302         }
303 
304         // log4j*.jar
305 
306         String[] log4jJars = pluginLibDir.list(
307             new GlobFilenameFilter("log4j*.jar"));
308 
309         if ((log4jJars == null) || (log4jJars.length == 0)) {
310             String portalJarPath = PortalUtil.getPortalLibDir() + "log4j.jar";
311 
312             FileUtil.copyFile(
313                 portalJarPath, srcFile + "/WEB-INF/lib/log4j.jar", true);
314         }
315     }
316 
317     protected void copyProperties(File srcFile, PluginPackage pluginPackage)
318         throws Exception {
319 
320         copyDependencyXml("log4j.properties", srcFile + "/WEB-INF/classes");
321         copyDependencyXml("logging.properties", srcFile + "/WEB-INF/classes");
322     }
323 
324     protected void copyTlds(File srcFile, PluginPackage pluginPackage)
325         throws Exception {
326 
327         if (Validator.isNotNull(portletTaglibDTD)) {
328             FileUtil.copyFile(
329                 portletTaglibDTD, srcFile + "/WEB-INF/tld/liferay-portlet.tld",
330                 true);
331         }
332 
333         if (Validator.isNotNull(portletExtTaglibDTD)) {
334             FileUtil.copyFile(
335                 portletExtTaglibDTD,
336                 srcFile + "/WEB-INF/tld/liferay-portlet-ext.tld", true);
337         }
338 
339         if (Validator.isNotNull(securityTaglibDTD)) {
340             FileUtil.copyFile(
341                 securityTaglibDTD,
342                 srcFile + "/WEB-INF/tld/liferay-security.tld", true);
343         }
344 
345         if (Validator.isNotNull(themeTaglibDTD)) {
346             FileUtil.copyFile(
347                 themeTaglibDTD, srcFile + "/WEB-INF/tld/liferay-theme.tld",
348                 true);
349         }
350 
351         if (Validator.isNotNull(uiTaglibDTD)) {
352             FileUtil.copyFile(
353                 uiTaglibDTD, srcFile + "/WEB-INF/tld/liferay-ui.tld", true);
354         }
355 
356         if (Validator.isNotNull(utilTaglibDTD)) {
357             FileUtil.copyFile(
358                 utilTaglibDTD, srcFile + "/WEB-INF/tld/liferay-util.tld", true);
359         }
360     }
361 
362     protected void copyXmls(
363             File srcFile, String displayName, PluginPackage pluginPackage)
364         throws Exception {
365 
366         if (appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
367             copyDependencyXml("geronimo-web.xml", srcFile + "/WEB-INF");
368         }
369 
370         copyDependencyXml("web.xml", srcFile + "/WEB-INF");
371     }
372 
373     protected void deploy() throws Exception {
374         try {
375             File baseDirFile = new File(baseDir);
376 
377             File[] files = baseDirFile.listFiles();
378 
379             if (files == null) {
380                 return;
381             }
382 
383             files = FileUtil.sortFiles(files);
384 
385             for (int i = 0; i < files.length; i++) {
386                 File srcFile = files[i];
387 
388                 String fileName = srcFile.getName().toLowerCase();
389 
390                 boolean deploy = false;
391 
392                 if (fileName.endsWith(".war") || fileName.endsWith(".zip")) {
393                     deploy = true;
394 
395                     if (wars.size() > 0) {
396                         if (!wars.contains(srcFile.getName())) {
397                             deploy = false;
398                         }
399                     }
400                     else if (Validator.isNotNull(filePattern)) {
401                         if (!StringUtil.matches(fileName, filePattern)) {
402                             deploy = false;
403                         }
404                     }
405                 }
406 
407                 if (deploy) {
408                     deployFile(srcFile);
409                 }
410             }
411         }
412         catch (Exception e) {
413             e.printStackTrace();
414         }
415     }
416 
417     protected void deployDirectory(
418             File srcFile, String displayName, boolean override,
419             PluginPackage pluginPackage)
420         throws Exception {
421 
422         deployDirectory(
423             srcFile, null, null, displayName, override, pluginPackage);
424     }
425 
426     protected void deployDirectory(
427             File srcFile, File mergeDir, File deployDir, String displayName,
428             boolean overwrite, PluginPackage pluginPackage)
429         throws Exception {
430 
431         rewriteFiles(srcFile);
432 
433         mergeDirectory(mergeDir, srcFile);
434 
435         processPluginPackageProperties(srcFile, displayName, pluginPackage);
436 
437         copyJars(srcFile, pluginPackage);
438         copyProperties(srcFile, pluginPackage);
439         copyTlds(srcFile, pluginPackage);
440         copyXmls(srcFile, displayName, pluginPackage);
441         copyPortalDependencies(srcFile);
442 
443         updateGeronimoWebXml(srcFile, displayName, pluginPackage);
444 
445         File webXml = new File(srcFile + "/WEB-INF/web.xml");
446 
447         updateWebXml(webXml, srcFile, displayName, pluginPackage);
448 
449         if ((deployDir != null) && !baseDir.equals(destDir)) {
450             updateDeployDirectory(srcFile);
451 
452             String excludes = StringPool.BLANK;
453 
454             if (appServerType.startsWith("jboss")) {
455                 excludes += "**/WEB-INF/lib/log4j.jar,";
456             }
457             else if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
458                 String[] libs = FileUtil.listFiles(tomcatLibDir);
459 
460                 for (int i = 0; i < libs.length; i++) {
461                     excludes += "**/WEB-INF/lib/" + libs[i] + ",";
462                 }
463 
464                 File contextXml = new File(srcFile + "/META-INF/context.xml");
465 
466                 if (contextXml.exists()) {
467                     String content = FileUtil.read(contextXml);
468 
469                     if (content.indexOf(_PORTAL_CLASS_LOADER) != -1) {
470                         excludes += "**/WEB-INF/lib/util-bridges.jar,";
471                         excludes += "**/WEB-INF/lib/util-java.jar,";
472                         excludes += "**/WEB-INF/lib/util-taglib.jar,";
473                     }
474                 }
475 
476                 try {
477 
478                     // LEP-2990
479 
480                     Class.forName("javax.el.ELContext");
481 
482                     excludes += "**/WEB-INF/lib/el-api.jar,";
483                 }
484                 catch (ClassNotFoundException cnfe) {
485                 }
486             }
487 
488             if (!unpackWar || appServerType.equals("websphere")) {
489                 File tempDir = new File(
490                     SystemProperties.get(SystemProperties.TMP_DIR) +
491                         File.separator + Time.getTimestamp());
492 
493                 WarTask.war(srcFile, tempDir, "WEB-INF/web.xml", webXml);
494 
495                 if (!tempDir.renameTo(deployDir)) {
496                     WarTask.war(srcFile, deployDir, "WEB-INF/web.xml", webXml);
497                 }
498 
499                 DeleteTask.deleteDirectory(tempDir);
500             }
501             else {
502 
503                 // The deployer might only copy files that have been modified.
504                 // However, the deployer always copies and overwrites web.xml
505                 // after the other files have been copied because application
506                 // servers usually detect that a WAR has been modified based on
507                 // the web.xml time stamp.
508 
509                 excludes += "**/WEB-INF/web.xml";
510 
511                 CopyTask.copyDirectory(
512                     srcFile, deployDir, StringPool.BLANK, excludes, overwrite,
513                     true);
514 
515                 CopyTask.copyDirectory(
516                     srcFile, deployDir, "**/WEB-INF/web.xml", StringPool.BLANK,
517                     true, false);
518 
519                 if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
520 
521                     // See org.apache.catalina.startup.HostConfig to see how
522                     // Tomcat checks to make sure that web.xml was modified 5
523                     // seconds after WEB-INF
524 
525                     File deployWebXml = new File(
526                         deployDir + "/WEB-INF/web.xml");
527 
528                     deployWebXml.setLastModified(
529                         System.currentTimeMillis() + (Time.SECOND * 6));
530                 }
531             }
532         }
533     }
534 
535     protected void deployFile(File srcFile) throws Exception {
536         PluginPackage pluginPackage = readPluginPackage(srcFile);
537 
538         if (_log.isInfoEnabled()) {
539             _log.info("Deploying " + srcFile.getName());
540         }
541 
542         String deployDir = null;
543         String displayName = null;
544         boolean overwrite = false;
545         String preliminaryContext = null;
546 
547         // File names starting with DEPLOY_TO_PREFIX should use the filename
548         // after the prefix as the deployment context
549 
550         if (srcFile.getName().startsWith(DEPLOY_TO_PREFIX)) {
551             displayName = srcFile.getName().substring(
552                 DEPLOY_TO_PREFIX.length(), srcFile.getName().length() - 4);
553 
554             overwrite = true;
555             preliminaryContext = displayName;
556         }
557 
558         if (preliminaryContext == null) {
559             preliminaryContext = getDisplayName(srcFile);
560         }
561 
562         if (pluginPackage != null) {
563             if (!PluginPackageUtil.isCurrentVersionSupported(
564                     pluginPackage.getLiferayVersions())) {
565 
566                 throw new AutoDeployException(
567                     srcFile.getName() +
568                         " does not support this version of Liferay");
569             }
570 
571             if (displayName == null) {
572                 displayName = pluginPackage.getRecommendedDeploymentContext();
573             }
574 
575             if (Validator.isNull(displayName)) {
576                 displayName = getDisplayName(srcFile);
577             }
578 
579             pluginPackage.setContext(displayName);
580 
581             PluginPackageUtil.updateInstallingPluginPackage(
582                 preliminaryContext, pluginPackage);
583         }
584 
585         if (Validator.isNotNull(displayName)) {
586             deployDir = displayName + ".war";
587         }
588         else {
589             deployDir = srcFile.getName();
590             displayName = getDisplayName(srcFile);
591         }
592 
593         if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
594             deployDir = jbossPrefix + deployDir;
595         }
596         else if (appServerType.equals(ServerDetector.JETTY_ID) ||
597                  appServerType.equals(ServerDetector.OC4J_ID) ||
598                  appServerType.equals(ServerDetector.ORION_ID) ||
599                  appServerType.equals(ServerDetector.RESIN_ID) ||
600                  appServerType.equals(ServerDetector.TOMCAT_ID)) {
601 
602             if (unpackWar) {
603                 deployDir = deployDir.substring(0, deployDir.length() - 4);
604             }
605         }
606 
607         deployDir = destDir + "/" + deployDir;
608 
609         File deployDirFile = new File(deployDir);
610 
611         try {
612             PluginPackage previousPluginPackage =
613                 readPluginPackage(deployDirFile);
614 
615             if ((pluginPackage != null) && (previousPluginPackage != null)) {
616                 if (_log.isInfoEnabled()) {
617                     String name = pluginPackage.getName();
618                     String previousVersion = previousPluginPackage.getVersion();
619                     String version = pluginPackage.getVersion();
620 
621                     _log.info(
622                         "Updating " + name + " from version " +
623                             previousVersion + " to version " + version);
624                 }
625 
626                 if (pluginPackage.isLaterVersionThan(
627                     previousPluginPackage)) {
628 
629                     overwrite = true;
630                 }
631             }
632 
633             File mergeDirFile = new File(
634                 srcFile.getParent() + "/merge/" + srcFile.getName());
635 
636             if (srcFile.isDirectory()) {
637                 deployDirectory(
638                     srcFile, mergeDirFile, deployDirFile, displayName,
639                     overwrite, pluginPackage);
640             }
641             else {
642                 boolean deployed = deployFile(
643                     srcFile, mergeDirFile, deployDirFile, displayName,
644                     overwrite, pluginPackage);
645 
646                 if (!deployed) {
647                     String context = preliminaryContext;
648 
649                     if (pluginPackage != null) {
650                         context = pluginPackage.getContext();
651                     }
652 
653                     PluginPackageUtil.endPluginPackageInstallation(context);
654                 }
655             }
656         }
657         catch (Exception e) {
658             if (pluginPackage != null) {
659                 PluginPackageUtil.endPluginPackageInstallation(
660                     pluginPackage.getContext());
661             }
662 
663             throw e;
664         }
665     }
666 
667     protected boolean deployFile(
668             File srcFile, File mergeDir, File deployDir, String displayName,
669             boolean overwrite, PluginPackage pluginPackage)
670         throws Exception {
671 
672         boolean undeployOnRedeploy = false;
673 
674         try {
675             undeployOnRedeploy = PrefsPropsUtil.getBoolean(
676                 PropsKeys.HOT_UNDEPLOY_ON_REDEPLOY,
677                 PropsValues.HOT_UNDEPLOY_ON_REDEPLOY);
678         }
679         catch (Exception e) {
680 
681             // This will only happen when running the deploy tool in Ant in the
682             // classical way where the WAR file is actually massaged and
683             // packaged.
684 
685         }
686 
687         if (undeployOnRedeploy) {
688             DeployUtil.undeploy(appServerType, deployDir);
689         }
690 
691         if (!overwrite && UpToDateTask.isUpToDate(srcFile, deployDir)) {
692             if (_log.isInfoEnabled()) {
693                 _log.info(deployDir + " is already up to date");
694             }
695 
696             return false;
697         }
698 
699         File tempDir = new File(
700             SystemProperties.get(SystemProperties.TMP_DIR) + File.separator +
701                 Time.getTimestamp());
702 
703         if ((PropsValues.PORTLET_CONTAINER_IMPL_SUN) &&
704             (this instanceof PortletDeployer)) {
705 
706             File sunTempDir = new File(
707                 SystemProperties.get(SystemProperties.TMP_DIR) +
708                     File.separator + "sun" + File.separator +
709                         Time.getTimestamp());
710 
711             Properties properties = new Properties();
712 
713             properties.setProperty(PortletWarUpdater.ADD_WEB_XML, "true");
714 
715             PortletWarUpdater warUpdater = new PortletWarUpdater(properties);
716 
717             boolean success = warUpdater.preparePortlet(
718                 srcFile, sunTempDir.toString());
719 
720             if (success){
721                 File sunSrcFile = new File(
722                     sunTempDir + File.separator + srcFile.getName());
723 
724                 ExpandTask.expand(sunSrcFile, tempDir);
725             }
726             else {
727                 ExpandTask.expand(srcFile, tempDir);
728             }
729 
730             deployDirectory(
731                 tempDir, mergeDir, deployDir, displayName, overwrite,
732                 pluginPackage);
733 
734             DeleteTask.deleteDirectory(sunTempDir);
735         }
736         else {
737             ExpandTask.expand(srcFile, tempDir);
738 
739             deployDirectory(
740                 tempDir, mergeDir, deployDir, displayName, overwrite,
741                 pluginPackage);
742         }
743 
744         DeleteTask.deleteDirectory(tempDir);
745 
746         return true;
747     }
748 
749     protected String downloadJar(String jar) throws Exception {
750         String tmpDir = SystemProperties.get(SystemProperties.TMP_DIR);
751 
752         File file = new File(
753             tmpDir + "/liferay/com/liferay/portal/deploy/dependencies/" +
754                 jar);
755 
756         if (!file.exists()) {
757             synchronized (this) {
758                 String url = PropsUtil.get(
759                     PropsKeys.LIBRARY_DOWNLOAD_URL + jar);
760 
761                 if (_log.isInfoEnabled()) {
762                     _log.info("Downloading library from " + url);
763                 }
764 
765                 byte[] bytes = HttpUtil.URLtoByteArray(url);
766 
767                 FileUtil.write(file, bytes);
768             }
769         }
770 
771         return FileUtil.getAbsolutePath(file);
772     }
773 
774     protected String getDisplayName(File srcFile) {
775         String displayName = srcFile.getName();
776 
777         if (StringUtil.endsWith(displayName, ".war") ||
778             StringUtil.endsWith(displayName, ".xml")) {
779 
780             displayName = displayName.substring(0, displayName.length() - 4);
781         }
782 
783         if (appServerType.startsWith("jboss") &&
784             Validator.isNotNull(jbossPrefix) &&
785             displayName.startsWith(jbossPrefix)) {
786 
787             displayName = displayName.substring(1, displayName.length());
788         }
789 
790         return displayName;
791     }
792 
793     protected String getExtraContent(
794             double webXmlVersion, File srcFile, String displayName)
795         throws Exception {
796 
797         StringBuilder sb = new StringBuilder();
798 
799         sb.append("<display-name>");
800         sb.append(displayName);
801         sb.append("</display-name>");
802 
803         File serviceXml = new File(srcFile + "/WEB-INF/service.xml");
804 
805         if (serviceXml.exists()) {
806             sb.append("<listener>");
807             sb.append("<listener-class>");
808             sb.append("com.liferay.portal.kernel.spring.context.");
809             sb.append("PortletContextLoaderListener");
810             sb.append("</listener-class>");
811             sb.append("</listener>");
812         }
813 
814         boolean hasTaglib = false;
815 
816         if (Validator.isNotNull(portletTaglibDTD) ||
817             Validator.isNotNull(portletExtTaglibDTD) ||
818             Validator.isNotNull(securityTaglibDTD) ||
819             Validator.isNotNull(themeTaglibDTD) ||
820             Validator.isNotNull(uiTaglibDTD) ||
821             Validator.isNotNull(utilTaglibDTD)) {
822 
823             hasTaglib = true;
824         }
825 
826         if (hasTaglib && (webXmlVersion > 2.3)) {
827             sb.append("<jsp-config>");
828         }
829 
830         if (Validator.isNotNull(portletTaglibDTD)) {
831             sb.append("<taglib>");
832             sb.append(
833                 "<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>");
834             sb.append("<taglib-location>");
835             sb.append("/WEB-INF/tld/liferay-portlet.tld");
836             sb.append("</taglib-location>");
837             sb.append("</taglib>");
838         }
839 
840         if (Validator.isNotNull(portletExtTaglibDTD)) {
841             sb.append("<taglib>");
842             sb.append("<taglib-uri>");
843             sb.append("http://liferay.com/tld/portlet");
844             sb.append("</taglib-uri>");
845             sb.append("<taglib-location>");
846             sb.append("/WEB-INF/tld/liferay-portlet-ext.tld");
847             sb.append("</taglib-location>");
848             sb.append("</taglib>");
849         }
850 
851         if (Validator.isNotNull(securityTaglibDTD)) {
852             sb.append("<taglib>");
853             sb.append("<taglib-uri>");
854             sb.append("http://liferay.com/tld/security");
855             sb.append("</taglib-uri>");
856             sb.append("<taglib-location>");
857             sb.append("/WEB-INF/tld/liferay-security.tld");
858             sb.append("</taglib-location>");
859             sb.append("</taglib>");
860         }
861 
862         if (Validator.isNotNull(themeTaglibDTD)) {
863             sb.append("<taglib>");
864             sb.append("<taglib-uri>http://liferay.com/tld/theme</taglib-uri>");
865             sb.append("<taglib-location>");
866             sb.append("/WEB-INF/tld/liferay-theme.tld");
867             sb.append("</taglib-location>");
868             sb.append("</taglib>");
869         }
870 
871         if (Validator.isNotNull(uiTaglibDTD)) {
872             sb.append("<taglib>");
873             sb.append("<taglib-uri>http://liferay.com/tld/ui</taglib-uri>");
874             sb.append("<taglib-location>");
875             sb.append("/WEB-INF/tld/liferay-ui.tld");
876             sb.append("</taglib-location>");
877             sb.append("</taglib>");
878         }
879 
880         if (Validator.isNotNull(utilTaglibDTD)) {
881             sb.append("<taglib>");
882             sb.append("<taglib-uri>http://liferay.com/tld/util</taglib-uri>");
883             sb.append("<taglib-location>");
884             sb.append("/WEB-INF/tld/liferay-util.tld");
885             sb.append("</taglib-location>");
886             sb.append("</taglib>");
887         }
888 
889         if (hasTaglib && (webXmlVersion > 2.3)) {
890             sb.append("</jsp-config>");
891         }
892 
893         return sb.toString();
894     }
895 
896     protected String getPluginPackageLicensesXml(List<License> licenses) {
897         StringBuilder sb = new StringBuilder();
898 
899         for (int i = 0; i < licenses.size(); i++) {
900             License license = licenses.get(i);
901 
902             if (i == 0) {
903                 sb.append("\r\n");
904             }
905 
906             sb.append("\t\t<license osi-approved=\"");
907             sb.append(license.isOsiApproved());
908             sb.append("\">");
909             sb.append(license.getName());
910             sb.append("</license>\r\n");
911 
912             if ((i + 1) == licenses.size()) {
913                 sb.append("\t");
914             }
915         }
916 
917         return sb.toString();
918     }
919 
920     protected String getPluginPackageLiferayVersionsXml(
921         List<String> liferayVersions) {
922 
923         StringBuilder sb = new StringBuilder();
924 
925         for (int i = 0; i < liferayVersions.size(); i++) {
926             String liferayVersion = liferayVersions.get(i);
927 
928             if (i == 0) {
929                 sb.append("\r\n");
930             }
931 
932             sb.append("\t\t<liferay-version>");
933             sb.append(liferayVersion);
934             sb.append("</liferay-version>\r\n");
935 
936             if ((i + 1) == liferayVersions.size()) {
937                 sb.append("\t");
938             }
939         }
940 
941         return sb.toString();
942     }
943 
944     protected Properties getPluginPackageProperties(File srcFile)
945         throws Exception {
946 
947         File propertiesFile = new File(
948             srcFile + "/WEB-INF/liferay-plugin-package.properties");
949 
950         if (!propertiesFile.exists()) {
951             return null;
952         }
953 
954         String propertiesString = FileUtil.read(propertiesFile);
955 
956         return PropertiesUtil.load(propertiesString);
957     }
958 
959     protected String getPluginPackageTagsXml(List<String> tags) {
960         StringBuilder sb = new StringBuilder();
961 
962         for (int i = 0; i < tags.size(); i++) {
963             String tag = tags.get(i);
964 
965             if (i == 0) {
966                 sb.append("\r\n");
967             }
968 
969             sb.append("\t\t<tag>");
970             sb.append(tag);
971             sb.append("</tag>\r\n");
972 
973             if ((i + 1) == tags.size()) {
974                 sb.append("\t");
975             }
976         }
977 
978         return sb.toString();
979     }
980 
981     protected String getSpeedFiltersContent(File srcFile) throws Exception {
982         boolean speedFiltersEnabled = true;
983 
984         Properties properties = getPluginPackageProperties(srcFile);
985 
986         if (properties != null) {
987             speedFiltersEnabled = GetterUtil.getBoolean(
988                 properties.getProperty("speed-filters-enabled"), true);
989         }
990 
991         if (speedFiltersEnabled) {
992             String speedFiltersContent = FileUtil.read(
993                 DeployUtil.getResourcePath("speed_filters.xml"));
994 
995             return speedFiltersContent;
996         }
997         else {
998             return StringPool.BLANK;
999         }
1000    }
1001
1002    protected void mergeDirectory(File mergeDir, File targetDir) {
1003        if ((mergeDir == null) || (!mergeDir.exists())) {
1004            return;
1005        }
1006
1007        CopyTask.copyDirectory(mergeDir, targetDir, null, null, true, false);
1008    }
1009
1010    protected void processPluginPackageProperties(
1011            File srcFile, String displayName, PluginPackage pluginPackage)
1012        throws Exception {
1013    }
1014
1015    protected PluginPackage readPluginPackage(File file) {
1016        if (!file.exists()) {
1017            return null;
1018        }
1019
1020        InputStream is = null;
1021        ZipFile zipFile = null;
1022
1023        try {
1024            boolean parseProps = false;
1025
1026            if (file.isDirectory()) {
1027                String path = file.getPath();
1028
1029                File pluginPackageXmlFile = new File(
1030                    file.getParent() + "/merge/" + file.getName() +
1031                        "/WEB-INF/liferay-plugin-package.xml");
1032
1033                if (pluginPackageXmlFile.exists()) {
1034                    is = new FileInputStream(pluginPackageXmlFile);
1035                }
1036                else {
1037                    pluginPackageXmlFile = new File(
1038                        path + "/WEB-INF/liferay-plugin-package.xml");
1039
1040                    if (pluginPackageXmlFile.exists()) {
1041                        is = new FileInputStream(pluginPackageXmlFile);
1042                    }
1043                }
1044
1045                File pluginPackagePropsFile = new File(
1046                    file.getParent() + "/merge/" + file.getName() +
1047                        "/WEB-INF/liferay-plugin-package.properties");
1048
1049                if ((is == null) && pluginPackagePropsFile.exists()) {
1050                    is = new FileInputStream(pluginPackagePropsFile);
1051
1052                    parseProps = true;
1053                }
1054                else {
1055                    pluginPackagePropsFile = new File(
1056                        path + "/WEB-INF/liferay-plugin-package.properties");
1057
1058                    if ((is == null) && pluginPackagePropsFile.exists()) {
1059                        is = new FileInputStream(pluginPackagePropsFile);
1060
1061                        parseProps = true;
1062                    }
1063                }
1064            }
1065            else {
1066                zipFile = new ZipFile(file);
1067
1068                File pluginPackageXmlFile = new File(
1069                    file.getParent() + "/merge/" + file.getName() +
1070                        "/WEB-INF/liferay-plugin-package.xml");
1071
1072                if (pluginPackageXmlFile.exists()) {
1073                    is = new FileInputStream(pluginPackageXmlFile);
1074                }
1075                else {
1076                    ZipEntry zipEntry = zipFile.getEntry(
1077                        "WEB-INF/liferay-plugin-package.xml");
1078
1079                    if (zipEntry != null) {
1080                        is = zipFile.getInputStream(zipEntry);
1081                    }
1082                }
1083
1084                File pluginPackagePropsFile = new File(
1085                    file.getParent() + "/merge/" + file.getName() +
1086                        "/WEB-INF/liferay-plugin-package.properties");
1087
1088                if ((is == null) && pluginPackagePropsFile.exists()) {
1089                    is = new FileInputStream(pluginPackagePropsFile);
1090
1091                    parseProps = true;
1092                }
1093                else {
1094                    ZipEntry zipEntry = zipFile.getEntry(
1095                        "WEB-INF/liferay-plugin-package.properties");
1096
1097                    if ((is == null) && (zipEntry != null)) {
1098                        is = zipFile.getInputStream(zipEntry);
1099
1100                        parseProps = true;
1101                    }
1102                }
1103            }
1104
1105            if (is == null) {
1106                if (_log.isInfoEnabled()) {
1107                    _log.info(
1108                        file.getPath() + " does not have a " +
1109                            "WEB-INF/liferay-plugin-package.xml or " +
1110                                "WEB-INF/liferay-plugin-package.properties");
1111                }
1112
1113                return null;
1114            }
1115
1116            if (parseProps) {
1117                String displayName = getDisplayName(file);
1118
1119                String propertiesString = StringUtil.read(is);
1120
1121                Properties properties = PropertiesUtil.load(propertiesString);
1122
1123                return PluginPackageUtil.readPluginPackageProps(
1124                    displayName, properties);
1125            }
1126            else {
1127                String xml = StringUtil.read(is);
1128
1129                xml = XMLFormatter.fixProlog(xml);
1130
1131                return PluginPackageUtil.readPluginPackageXml(xml);
1132            }
1133        }
1134        catch (Exception e) {
1135            _log.error(file.getPath() + ": " + e.toString());
1136        }
1137        finally {
1138            if (is != null) {
1139                try {
1140                    is.close();
1141                }
1142                catch (IOException ioe) {
1143                }
1144            }
1145
1146            if (zipFile != null) {
1147                try {
1148                    zipFile.close();
1149                }
1150                catch (IOException ioe) {
1151                }
1152            }
1153        }
1154
1155        return null;
1156    }
1157
1158    protected void rewriteFiles(File srcDir) throws Exception {
1159        String[] files = FileUtil.listFiles(srcDir + "/WEB-INF/");
1160
1161        for (int i = 0; i < files.length; i++) {
1162            String fileName = GetterUtil.getString(
1163                FileUtil.getShortFileName(files[i]));
1164
1165            // LEP-6415
1166
1167            if (fileName.equalsIgnoreCase("mule-config.xml")) {
1168                continue;
1169            }
1170
1171            String ext = GetterUtil.getString(FileUtil.getExtension(files[i]));
1172
1173            if (!ext.equalsIgnoreCase("xml")) {
1174                continue;
1175            }
1176
1177            // Make sure to rewrite any XML files to include external entities
1178            // into same file. See LEP-3142.
1179
1180            File file = new File(srcDir + "/WEB-INF/" + files[i]);
1181
1182            try {
1183                Document doc = SAXReaderUtil.read(file);
1184
1185                String content = doc.formattedString(StringPool.TAB, true);
1186
1187                FileUtil.write(file, content);
1188            }
1189            catch (Exception e) {
1190                if (_log.isWarnEnabled()) {
1191                    _log.warn(
1192                        "Unable to format " + file + ": " + e.getMessage());
1193                }
1194            }
1195        }
1196    }
1197
1198    protected void updateDeployDirectory(File srcFile) throws Exception {
1199    }
1200
1201    protected void updateGeronimoWebXml(
1202            File srcFile, String displayName, PluginPackage pluginPackage)
1203        throws Exception {
1204
1205        if (!appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
1206            return;
1207        }
1208
1209        File geronimoWebXml = new File(srcFile + "/WEB-INF/geronimo-web.xml");
1210
1211        Document doc = SAXReaderUtil.read(geronimoWebXml);
1212
1213        Element root = doc.getRootElement();
1214
1215        Element environmentEl = root.element("environment");
1216
1217        Element moduleIdEl = environmentEl.element("moduleId");
1218
1219        Element artifactIdEl = moduleIdEl.element("artifactId");
1220
1221        String artifactIdText = GetterUtil.getString(artifactIdEl.getText());
1222
1223        if (!artifactIdText.equals(displayName)) {
1224            artifactIdEl.setText(displayName);
1225
1226            String content = doc.formattedString();
1227
1228            FileUtil.write(geronimoWebXml, content);
1229
1230            if (_log.isInfoEnabled()) {
1231                _log.info("Modifying Geronimo " + geronimoWebXml);
1232            }
1233        }
1234    }
1235
1236    protected void updateWebXml(
1237            File webXml, File srcFile, String displayName,
1238            PluginPackage pluginPackage)
1239        throws Exception {
1240
1241        String content = FileUtil.read(webXml);
1242
1243        int x = content.indexOf("<display-name>");
1244
1245        if (x != -1) {
1246            int y = content.indexOf("</display-name>", x);
1247
1248            y = content.indexOf(">", y) + 1;
1249
1250            content = content.substring(0, x) + content.substring(y);
1251        }
1252
1253        double webXmlVersion = 2.3;
1254
1255        Document webXmlDoc = SAXReaderUtil.read(content);
1256
1257        Element webXmlRoot = webXmlDoc.getRootElement();
1258
1259        webXmlVersion = GetterUtil.getDouble(
1260            webXmlRoot.attributeValue("version"), webXmlVersion);
1261
1262        // Merge extra content
1263
1264        String extraContent = getExtraContent(
1265            webXmlVersion, srcFile, displayName);
1266
1267        int pos = content.indexOf("</web-app>");
1268
1269        String newContent =
1270            content.substring(0, pos) + extraContent +
1271            content.substring(pos, content.length());
1272
1273        // Replace old package names
1274
1275        newContent = StringUtil.replace(
1276            newContent, "com.liferay.portal.shared.",
1277            "com.liferay.portal.kernel.");
1278
1279        newContent = WebXMLBuilder.organizeWebXML(newContent);
1280
1281        FileUtil.write(webXml, newContent, true);
1282
1283        if (_log.isInfoEnabled()) {
1284            _log.info("Modifying Servlet " + webXmlVersion + " " + webXml);
1285        }
1286    }
1287
1288    protected String baseDir;
1289    protected String destDir;
1290    protected String appServerType;
1291    protected String portletTaglibDTD;
1292    protected String portletExtTaglibDTD;
1293    protected String securityTaglibDTD;
1294    protected String themeTaglibDTD;
1295    protected String uiTaglibDTD;
1296    protected String utilTaglibDTD;
1297    protected boolean unpackWar;
1298    protected String filePattern;
1299    protected String jbossPrefix;
1300    protected String tomcatLibDir;
1301    protected List<String> wars;
1302    protected List<String> jars;
1303
1304    private static final String _PORTAL_CLASS_LOADER =
1305        "com.liferay.support.tomcat.loader.PortalClassLoader";
1306
1307    private static Log _log = LogFactoryUtil.getLog(BaseDeployer.class);
1308
1309}