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