View Javadoc
1   /*
2    * #%L
3    * settings4j
4    * ===============================================================
5    * Copyright (C) 2008 - 2015 Brabenetz Harald, Austria
6    * ===============================================================
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * 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   * #L%
19   */
20  package org.settings4j.objectresolver;
21  
22  import java.io.ByteArrayInputStream;
23  import java.io.IOException;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Properties;
27  
28  import org.apache.commons.lang3.StringUtils;
29  import org.settings4j.ContentResolver;
30  import org.settings4j.ObjectResolver;
31  
32  /**
33   * Basic Connector implementations like getter and Setter of contentResolver, objectResolver.
34   *
35   * @author Harald.Brabenetz
36   *
37   */
38  public abstract class AbstractObjectResolver implements ObjectResolver {
39  
40      /** General Logger for this Class. */
41      private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(AbstractObjectResolver.class);
42  
43      /** The Key which ObjectResolver implementation should be used. */
44      public static final String PROP_OBJECT_RESOLVER_KEY = "objectResolverKey";
45      /** The Key if the found Object should be cached (this will handle the Object as singleton). */
46      public static final String PROP_CACHED = "cached";
47  
48      private String propertySuffix = ".properties";
49  
50      private final Map<String, Object> cachedObjects = new HashMap<String, Object>();
51  
52      private boolean cached;
53  
54      @Override
55      public void addObjectResolver(final ObjectResolver objectResolver) {
56          throw new UnsupportedOperationException(this.getClass().getName() + " cannot add other ObjectResolvers");
57      }
58  
59      @Override
60      public Object getObject(final String key, final ContentResolver contentResolver) {
61  
62          Object result = this.cachedObjects.get(key);
63          if (result != null) {
64              return result;
65          }
66  
67  
68          final byte[] content = contentResolver.getContent(key);
69          if (content == null) {
70              return null;
71          }
72          final Properties properties = getObjectProperties(key, contentResolver);
73          if (properties == null) {
74              return null;
75          }
76  
77          final String propObjectResolverKey = properties.getProperty(PROP_OBJECT_RESOLVER_KEY);
78          if (StringUtils.isEmpty(propObjectResolverKey)) {
79              LOG.warn("The property-File for Key '{}' doesn't have the required Property '{}'", //
80                  key, PROP_OBJECT_RESOLVER_KEY);
81              return null;
82          }
83          if (!getObjectResolverKey().equals(propObjectResolverKey)) {
84              return null;
85          }
86  
87          result = contentToObject(key, properties, content, contentResolver);
88          if (result != null) {
89              if (isCacheEnabled(properties)) {
90                  this.cachedObjects.put(key, result);
91              }
92              return result;
93          }
94          return null;
95      }
96  
97      private boolean isCacheEnabled(final Properties properties) {
98          final String propCached = properties.getProperty(PROP_CACHED);
99          return "true".equalsIgnoreCase(propCached) || (propCached == null && isCached());
100     }
101 
102     /**
103      * To get the additional Properties for the given byte[] content can be overwriten by subclasses.
104      * <p>
105      * The default implementation reads the PropertyFile from key + ".properties". If no property where found, or an error occurs, this method return null.
106      * </p>
107      *
108      * @param key
109      *        the key of the byte[] Content to convert.
110      * @param contentResolver
111      *        the ContentResolver to read the additional Property-File.
112      * @return the parsed {@link Properties} Object or null if an error occurred.
113      */
114     protected Properties getObjectProperties(final String key, final ContentResolver contentResolver) {
115 
116         final byte[] propertyContent = contentResolver.getContent(key + this.propertySuffix);
117         if (propertyContent == null) {
118             return null;
119         }
120         // else
121         final Properties properties = new Properties();
122         try {
123             properties.load(new ByteArrayInputStream(propertyContent));
124         } catch (final IOException e) {
125             LOG.error(e.getMessage(), e);
126             return null;
127         }
128         return properties;
129 
130     }
131 
132     public String getPropertySuffix() {
133         return this.propertySuffix;
134     }
135 
136     public void setPropertySuffix(final String propertySuffix) {
137         this.propertySuffix = propertySuffix;
138     }
139 
140     protected String getObjectResolverKey() {
141         return this.getClass().getName();
142     }
143 
144     /**
145      * Method to convert the given content-File to an Object must be implemented by SubClasses.
146      *
147      * @param key The Original Key of the Object
148      * @param properties The Property-File which where Found under key + ".properties"
149      * @param content The byte[] Content to convert.
150      * @param contentResolver the contentResolver to get possible additional content Files.
151      * @return the parsed Object from the byte[] Content.
152      */
153     protected abstract Object contentToObject(String key, Properties properties, byte[] content,
154         ContentResolver contentResolver);
155 
156     public boolean isCached() {
157         return this.cached;
158     }
159 
160     public void setCached(final boolean cached) {
161         this.cached = cached;
162     }
163 }