View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.launcher;
8   
9   import org.mule.api.MuleRuntimeException;
10  import org.mule.config.PreferredObjectSelector;
11  import org.mule.config.i18n.MessageFactory;
12  import org.mule.module.launcher.descriptor.ApplicationDescriptor;
13  import org.mule.module.launcher.descriptor.DescriptorParser;
14  import org.mule.module.launcher.descriptor.EmptyApplicationDescriptor;
15  import org.mule.module.launcher.descriptor.PropertiesDescriptorParser;
16  import org.mule.module.reboot.MuleContainerBootstrapUtils;
17  import org.mule.util.FileUtils;
18  import org.mule.util.FilenameUtils;
19  import org.mule.util.PropertiesUtils;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.util.Properties;
28  
29  import javax.imageio.spi.ServiceRegistry;
30  
31  import org.apache.commons.collections.MultiMap;
32  import org.apache.commons.collections.map.MultiValueMap;
33  import org.apache.commons.io.filefilter.WildcardFileFilter;
34  
35  /**
36   *
37   */
38  public class DefaultAppBloodhound implements AppBloodhound
39  {
40  
41      // file extension -> parser implementation
42      protected Map<String, DescriptorParser> parserRegistry = new HashMap<String, DescriptorParser>();
43      public static final String SYSTEM_PROPERTY_OVERRIDE = "-O";
44  
45      public DefaultAppBloodhound()
46      {
47          // defaults first
48          parserRegistry.put("properties", new PropertiesDescriptorParser());
49  
50          final Iterator<DescriptorParser> it = ServiceRegistry.lookupProviders(DescriptorParser.class);
51  
52          MultiMap overrides = new MultiValueMap();
53          while (it.hasNext())
54          {
55              final DescriptorParser parser = it.next();
56              overrides.put(parser.getSupportedFormat(), parser);
57          }
58          mergeParserOverrides(overrides);
59      }
60  
61      public ApplicationDescriptor fetch(String appName) throws IOException
62      {
63          final File appsDir = MuleContainerBootstrapUtils.getMuleAppsDir();
64          File appDir = new File(appsDir, appName);
65          if (!appDir.exists())
66          {
67              throw new MuleRuntimeException(
68                      MessageFactory.createStaticMessage(
69                              String.format("Application directory does not exist: '%s'", appDir)));
70          }
71          // list mule-deploy.* files
72          @SuppressWarnings("unchecked")
73          Collection<File> deployFiles = FileUtils.listFiles(appDir, new WildcardFileFilter("mule-deploy.*"), null);
74          if (deployFiles.size() > 1)
75          {
76              // TODO need some kind of an InvalidAppFormatException
77              throw new MuleRuntimeException(
78                      MessageFactory.createStaticMessage(
79                              String.format("More than one mule-deploy descriptors found in application '%s'", appName)));
80          }
81  
82          ApplicationDescriptor desc;
83  
84          // none found, return defaults
85          if (deployFiles.isEmpty())
86          {
87              desc = new EmptyApplicationDescriptor(appName);
88          }
89          else
90          {
91              // lookup the implementation by extension
92              final File descriptorFile = deployFiles.iterator().next();
93              final String ext = FilenameUtils.getExtension(descriptorFile.getName());
94              final DescriptorParser descriptorParser = parserRegistry.get(ext);
95  
96              if (descriptorParser == null)
97              {
98                  // TODO need some kind of an InvalidAppFormatException
99                  throw new MuleRuntimeException(
100                         MessageFactory.createStaticMessage(
101                                 String.format("Unsupported deployment descriptor format for app '%s': %s", appName, ext)));
102             }
103 
104             desc = descriptorParser.parse(descriptorFile);
105             // app name is external to the deployment descriptor
106             desc.setAppName(appName);
107         }
108 
109         // get a ref to an optional app props file (right next to the descriptor)
110         final File appPropsFile = new File(appDir, ApplicationDescriptor.DEFAULT_APP_PROPERTIES_RESOURCE);
111         setApplicationProperties(desc, appPropsFile);
112         return desc;
113 
114     }
115 
116     public void setApplicationProperties(ApplicationDescriptor desc, File appPropsFile) throws IOException
117     {
118         // ugh, no straightforward way to convert a HashTable to a map
119         Map<String, String> m = new HashMap<String, String>();
120 
121         if (appPropsFile.exists() && appPropsFile.canRead())
122         {
123             final Properties props = PropertiesUtils.loadProperties(appPropsFile.toURI().toURL());
124             for (Object key : props.keySet())
125             {
126                 m.put(key.toString(), props.getProperty(key.toString()));
127             }
128         }
129 
130         // Override with any system properties prepended with "-O" for ("override"))
131         Properties sysProps = System.getProperties();
132         for (Map.Entry<Object, Object> entry : sysProps.entrySet())
133         {
134             String key = entry.getKey().toString();
135             if (key.startsWith(SYSTEM_PROPERTY_OVERRIDE))
136             {
137                 m.put(key.substring(SYSTEM_PROPERTY_OVERRIDE.length()), entry.getValue().toString());
138             }
139         }
140         desc.setAppProperties(m);
141     }
142 
143     /**
144      * Merge default and discovered overrides for descriptor parsers, taking weight into account
145      *
146      * @param overrides discovered parser overrides
147      */
148     protected void mergeParserOverrides(MultiMap overrides)
149     {
150         PreferredObjectSelector<DescriptorParser> selector = new PreferredObjectSelector<DescriptorParser>();
151 
152         for (Map.Entry<String, DescriptorParser> entry : parserRegistry.entrySet())
153         {
154             @SuppressWarnings("unchecked")
155             final Collection<DescriptorParser> candidates = (Collection<DescriptorParser>) overrides.get(entry.getKey());
156 
157             if (candidates != null)
158             {
159                 parserRegistry.put(entry.getKey(), selector.select(candidates.iterator()));
160             }
161         }
162 
163     }
164 }