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