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