View Javadoc
1   /*
2    * #%L
3    * Nuiton Decorator
4    * %%
5    * Copyright (C) 2011 CodeLutin, Tony Chemit
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as 
9    * published by the Free Software Foundation, either version 3 of the 
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public 
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20   * #L%
21   */
22  package org.nuiton.decorator;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  /**
31   * A decorator provider.
32   * <p/>
33   * Implements the method {@link #loadDecorators()} to fill the decorators
34   * availables.
35   * <p/>
36   * Then can obtain decorator via the methods {@code getDecorator(...)}
37   * <p/>
38   *
39   * @author tchemit <chemit@codelutin.com>
40   * @since 2.3
41   */
42  public abstract class DecoratorProvider {
43  
44      /** Logger */
45      private static final Log log = LogFactory.getLog(DecoratorProvider.class);
46  
47      /** Registred decorators. */
48      protected List<DecoratorContext<?>> decorators;
49  
50      public DecoratorProvider() {
51          loadDecorators();
52      }
53  
54      /** Load all decorators of the provider */
55      protected abstract void loadDecorators();
56  
57      /**
58       * Obtain a decorator for the given object.
59       *
60       * @param object object of decorated object
61       * @param <O>    object of decorated object
62       * @return the decorator or {@code null} if not found
63       */
64      @SuppressWarnings({"unchecked"})
65      public <O> Decorator<O> getDecorator(O object) {
66          return getDecorator(object, null);
67      }
68  
69      /**
70       * Obtain a decorator given a object and an extra name to qualify the
71       * context.
72       *
73       * @param object object of decorated object
74       * @param name   extra name to qualify the decorator to use
75       * @param <O>    object of decorated object
76       * @return the decorator or {@code null} if not found
77       */
78      @SuppressWarnings({"unchecked"})
79      public <O> Decorator<O> getDecorator(O object, String name) {
80          Class<O> k = (Class<O>) object.getClass();
81          return getDecoratorByType(k, name);
82      }
83  
84      /**
85       * Obtain a decorator given a type.
86       *
87       * @param type type of decorated object
88       * @param <O>  type of decorated object
89       * @return the decorator or {@code null} if not found
90       */
91      public <O> Decorator<O> getDecoratorByType(Class<O> type) {
92          return getDecoratorByType(type, null);
93      }
94  
95      /**
96       * Obtain a decorator given a type and a extra name.
97       *
98       * @param type type of decorated object
99       * @param name extra name to qualify the decorator to use
100      * @param <O>  type of decorated object
101      * @return the decorator or {@code null} if not found
102      */
103     public <O> Decorator<O> getDecoratorByType(Class<O> type, String name) {
104         DecoratorContext<O> d = getDecoratorContext(type, name);
105         return d == null ? null : d.getDecorator();
106     }
107 
108     public void reload() {
109         clear();
110         loadDecorators();
111     }
112 
113     public void registerPropertyDecorator(Class<?> klass,
114                                              String expression) {
115         registerPropertyDecorator(klass, null, expression);
116     }
117 
118     public void registerJXPathDecorator(Class<?> klass, String expression) {
119         registerJXPathDecorator(klass, null, expression);
120     }
121 
122     public void registerMultiJXPathDecorator(Class<?> klass,
123                                                 String expression,
124                                                 String separator,
125                                                 String separatorReplacement) {
126         registerMultiJXPathDecorator(klass, null, expression, separator,
127                                      separatorReplacement);
128     }
129 
130     public void registerPropertyDecorator(Class<?> klass,
131                                              String name,
132                                              String expression) {
133         Decorator<?> decorator =
134                 DecoratorUtil.newPropertyDecorator(klass, expression);
135         registerDecorator(name, decorator);
136     }
137 
138     public void registerJXPathDecorator(Class<?> klass,
139                                            String name,
140                                            String expression) {
141         Decorator<?> decorator =
142                 DecoratorUtil.newJXPathDecorator(klass, expression);
143         registerDecorator(name, decorator);
144     }
145 
146     public void registerMultiJXPathDecorator(Class<?> klass,
147                                                 String name,
148                                                 String expression,
149                                                 String separator,
150                                                 String separatorReplacement) {
151         Decorator<?> decorator = DecoratorUtil.newMultiJXPathDecorator(
152                 klass, expression, separator, separatorReplacement
153         );
154         registerDecorator(name, decorator);
155     }
156 
157     public void registerDecorator(Decorator<?> decorator) {
158         registerDecorator(null, decorator);
159     }
160 
161     /**
162      * Register a new decorator in the cache of the provider.
163      *
164      * @param <T>       type of data decorated
165      * @param context   the name decorator
166      * @param decorator the decorator to register
167      */
168     public <T> void registerDecorator(String context,
169                                          Decorator<T> decorator) {
170 
171         // obtain the decorator context
172         DecoratorContext<?> result =
173                 getDecoratorContext(decorator.getType(), context);
174 
175         if (result != null) {
176             throw new IllegalArgumentException(
177                     "there is an already register decorator with context " +
178                     result);
179         }
180 
181         DecoratorContext<T> decoratorContext =
182                 new DecoratorContext<T>(context, decorator);
183         if (log.isDebugEnabled()) {
184             log.debug(decoratorContext);
185         }
186         getDecorators().add(decoratorContext);
187     }
188 
189     public void clear() {
190         if (decorators != null) {
191             decorators.clear();
192         }
193     }
194 
195     protected List<DecoratorContext<?>> getDecorators() {
196         if (decorators == null) {
197             decorators = new ArrayList<DecoratorContext<?>>();
198         }
199         return decorators;
200     }
201 
202     @SuppressWarnings({"unchecked"})
203     protected <T> DecoratorContext<T> getDecoratorContext(Class<T> type,
204                                                           String context) {
205         DecoratorContext<T> result = null;
206         if (decorators != null) {
207             for (DecoratorContext<?> d : decorators) {
208                 if (type == null) {
209                     if (d.accept(context)) {
210                         result = (DecoratorContext<T>) d;
211                         break;
212                     }
213                     continue;
214                 }
215                 if (d.accept(type, context)) {
216                     result = (DecoratorContext<T>) d;
217                     break;
218                 }
219             }
220         }
221         return result;
222     }
223 
224     public static class DecoratorContext<T> {
225 
226         /** the context name of the decorator */
227         final String context;
228 
229         /** the decorator */
230         final Decorator<T> decorator;
231 
232         public DecoratorContext(String context, Decorator<T> decorator) {
233             this.context = context;
234             this.decorator = decorator;
235         }
236 
237         public String getContext() {
238             return context;
239         }
240 
241         public Decorator<T> getDecorator() {
242             return decorator;
243         }
244 
245         public Class<T> getType() {
246             return decorator.getType();
247         }
248 
249         public boolean accept(Class<?> type, String context) {
250             boolean accept = getType().isAssignableFrom(type) && accept(context);
251             return accept;
252         }
253 
254         public boolean accept(String context) {
255             return this.context == null && context == null ||
256                    this.context != null && this.context.equals(context);
257         }
258 
259         @Override
260         public String toString() {
261             return super.toString() + "<type: " + getType().getName() +
262                    ", context :" + context + ">";
263         }
264     }
265 
266 }