View Javadoc

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