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