View Javadoc

1   package org.apache.onami.autobind.configuration.features;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   *
11   *  http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  import static java.lang.String.format;
21  import static java.util.logging.Level.INFO;
22  import static java.util.logging.Level.WARNING;
23  import static java.util.logging.Logger.getLogger;
24  import static org.apache.onami.autobind.configuration.Configuration.Type.BOTH;
25  import static org.apache.onami.autobind.configuration.Configuration.Type.CONFIGURATION;
26  import static org.apache.onami.autobind.configuration.Configuration.Type.VALUES;
27  import static org.apache.onami.autobind.install.BindingStage.BOOT_BEFORE;
28  import static org.apache.onami.autobind.install.BindingStage.IGNORE;
29  
30  import java.io.File;
31  import java.lang.annotation.Annotation;
32  import java.net.MalformedURLException;
33  import java.net.URL;
34  import java.util.Map;
35  import java.util.Properties;
36  import java.util.logging.Logger;
37  
38  import javax.inject.Inject;
39  import javax.inject.Named;
40  import javax.inject.Provider;
41  import javax.inject.Singleton;
42  
43  import org.apache.onami.autobind.configuration.Configuration;
44  import org.apache.onami.autobind.configuration.ConfigurationBindingJob;
45  import org.apache.onami.autobind.configuration.ConfigurationModule;
46  import org.apache.onami.autobind.configuration.PathConfig;
47  import org.apache.onami.autobind.configuration.PropertiesProvider;
48  import org.apache.onami.autobind.install.BindingStage;
49  import org.apache.onami.autobind.install.bindjob.BindingJob;
50  import org.apache.onami.autobind.scanner.features.BindingScannerFeature;
51  import org.apache.onami.configuration.PropertiesURLReader;
52  
53  /**
54   * This class will bind a Properties-Instance or -Provider for each Class
55   * annotated with {@link Configuration}.
56   */
57  @Singleton
58  public class ConfigurationFeature
59      extends BindingScannerFeature
60  {
61  
62      private final Logger _logger = getLogger( getClass().getName() );
63  
64      @Inject
65      private ConfigurationModule module;
66  
67      @Override
68      public BindingStage accept( Class<Object> annotatedClass, Map<String, Annotation> annotations )
69      {
70          if ( annotations.containsKey( Configuration.class.getName() ) )
71          {
72              Configuration config = (Configuration) annotations.get( Configuration.class.getName() );
73              if ( Properties.class.isAssignableFrom( config.to() ) )
74              {
75                  return BOOT_BEFORE;
76              }
77          }
78          return IGNORE;
79      }
80  
81      @Override
82      public void process( Class<Object> annotatedClass, Map<String, Annotation> annotations )
83      {
84          Configuration config = (Configuration) annotations.get( Configuration.class.getName() );
85          Named name = config.name();
86  
87          URL url = null;
88          if ( config.alternative().value().length() > 0 )
89          {
90              url = findURL( name, config.alternative() );
91              if ( url != null )
92              {
93                  try
94                  {
95                      // TODO Use an Executor to test, if the Stream can be opened?
96                      // FIXME What happens if Error Page is returned?
97                      /*
98                       * final URL alternativeURL = url; Future<URL> submit =
99                       * Executors.newSingleThreadExecutor().submit(new Callable<URL>() {
100                      * @Override public URL call() throws Exception { alternativeURL.openConnection().getInputStream();
101                      * return alternativeURL; } }); submit.get(5, TimeUnit.SECONDS);
102                      */
103                     url.openStream();
104                 }
105                 catch ( Exception e )
106                 {
107                     url = null;
108                 }
109             }
110         }
111 
112         if ( url == null )
113         {
114             url = findURL( name, config.location() );
115         }
116 
117         if ( url == null )
118         {
119             _logger.log( WARNING, format( "Ignoring Configuration %s in %s because is couldn't be found in the Classpath.",
120                                           name, config.location() ) );
121             // TODO Throw an exception if config doesn't exist?
122             return;
123         }
124 
125         if ( VALUES == config.type() || BOTH == config.type() )
126         {
127             BindingJob job = new ConfigurationBindingJob( config.name(), url.toString() );
128             if ( !tracer.contains( job ) )
129             {
130                 /* && !(url.toString().startsWith("jar:")) */
131                 _logger.log( INFO, format( "Trying to bind \"%s\" to rocoto Module.", url ) );
132                 PropertiesURLReader reader = new PropertiesURLReader( url ); 
133                 if(url.toString().endsWith( ".xml" )){
134                 	reader.inXMLFormat();
135                 }
136                 module.addConfigurationReader( reader );
137                 // TODO do we need protocol handling? file:/, ...
138                 tracer.add( job );
139             }
140         }
141 
142         if ( CONFIGURATION == config.type() || BOTH == config.type() )
143         {
144             boolean isXML;
145             String path = url.toString();
146             if ( path.endsWith( ".xml" ) )
147             {
148                 isXML = true;
149             }
150             else if ( path.endsWith( ".properties" ) )
151             {
152                 isXML = false;
153             }
154             else
155             {
156                 _logger.log( WARNING, format( "Ignoring Configuration %s in %s because it doesn't end with .xml or .properties.",
157                                               name, config.location() ) );
158                 // TODO Throw an exception if config has another format?
159                 return;
160             }
161 
162             Named named = null;
163             if ( name.value().length() > 0 )
164             {
165                 named = name;
166             }
167 
168             if ( !config.lazy() )
169             {
170                 Properties properties;
171                 try
172                 {
173                 	PropertiesURLReader reader = new PropertiesURLReader( url ); 
174                     if(isXML){
175                     	reader.inXMLFormat();
176                     }
177                     properties = reader.readConfiguration();
178                 }
179                 catch ( Exception e )
180                 {
181                     _logger.log( WARNING, format( "Configuration %s in %s cannot be loaded: %s",
182                                                   name, url, e.getMessage() ), e );
183                     return;
184                 }
185 
186                 bindInstance( properties, Properties.class, named, null );
187             }
188             else
189             {
190                 Provider<Properties> provider = new PropertiesProvider( url, isXML );
191                 bindProvider( provider, Properties.class, named, Singleton.class );
192             }
193         }
194     }
195 
196     private URL findURL( Named name, PathConfig config )
197     {
198         URL url = null;
199         String path = resolver.resolve( config.value() );
200 
201         switch ( config.type() )
202         {
203             case FILE:
204                 File file = new File( path );
205                 if ( !file.exists() )
206                 {
207                     _logger.log( WARNING, format( "Ignoring Configuration %s in %s, no Configuration found in %s",
208                                                   name, path, file.getAbsolutePath() ) );
209                     return null;
210                 }
211                 if ( file.isFile() )
212                 {
213                     try
214                     {
215                         url = file.toURI().toURL();
216                     }
217                     catch ( MalformedURLException e )
218                     {
219                         _logger.log( WARNING, format( "Ignoring Configuration %s in %s due to illegal URL location",
220                                                       name, path ), e );
221                         return null;
222                     }
223                 } /*
224                    * else if (file.isDirectory()) { for (File entry : file.listFiles()) { try { url =
225                    * entry.toURI().toURL(); } catch (MalformedURLException e) { _logger.log(Level.WARNING,
226                    * "Ignoring Configuration " + name + " in " + path + ". It has an illegal URL-Format.", e); return
227                    * null; } } }
228                    */
229 
230                 break;
231 
232             case URL:
233                 try
234                 {
235                     url = new URL( path );
236                 }
237                 catch ( MalformedURLException e )
238                 {
239                     _logger.log( WARNING, format( "Ignoring Configuration %s in %s due to illegal URL location",
240                                                   name, path ), e );
241                     return null;
242                 }
243                 break;
244 
245             case CLASSPATH:
246             default:
247                 url = this.getClass().getResource( path );
248                 break;
249         }
250 
251         return url;
252     }
253 
254 }