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