View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.util;
20  
21  import javax.faces.context.FacesContext;
22  import javax.faces.render.RenderKit;
23  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
24  
25  /**
26   * <p>
27   * API for retrieving a service from an object.  Services 
28   * remove the need for a class to directly implement an interface;
29   * instead a class can implement the Service.Provider inner
30   * interface.  This makes it possible to "decorate" another
31   * generic class - like RenderKit - without needing to know
32   * in advance what optional interfaces the decorated object
33   * might implement, or to even switch on and off implementations
34   * dynamically.  A developer can still choose to directly
35   * implement an interface.  The {@link #getService} method
36   * supports both direct implementation and the use of 
37   * the Service.Provider interface.
38   * </p>
39   * 
40   * <p>
41   * <h4>Example:</h4>
42   * <pre>
43   *    RenderKit rk = facesContext.getRenderKit();
44   *    // Retrieve the DialogService generically.
45   *    DialogService service = (DialogService)
46   *      ServiceUtils.getService(rk, DialogService.class);
47   * </pre>
48   * </p>
49   */
50  public class Service
51  {
52    /**
53     * Inner interface that should be implemented if a class needs to
54     * provide services other than by the default approach.  Most often,
55     * this is used by decorators to re-expose any services implemented
56     * by the decorated object, but it may also be used to hide interfaces
57     * that should not be exposed (e.g., if a subclass wishes to hide
58     * interfaces implemented by its parent).
59     */
60    static public interface Provider
61    {
62      public <T> T getService(Class<T> serviceClass);
63    }
64  
65  
66    /**
67     * Returns a service that can be cast to the provided serviceClass,
68     * as vended by the <code>from</code> object.  If the class
69     * implements Provider, its <code>getService()</code> method will
70     * be used.  Otherwise, the default behavior will be to see
71     * if <code>from</code> is an instance of <code>serviceClass</code>,
72     * and return it if it is.
73     * @param from the object that is vending the service
74     * @param serviceClass the type of object that must be returned
75     * @return an object of type <code>serviceClass</code>, or null
76     *   if no such object could be located
77     */
78    @SuppressWarnings("unchecked")
79    static public <T> T getService(Object from, Class<T> serviceClass)
80    {
81      if (from == null)
82        throw new NullPointerException();
83  
84      if (from instanceof Provider)
85      {
86        T o = ((Provider) from).getService(serviceClass);
87        if (o != null)
88        {
89          if (!serviceClass.isAssignableFrom(o.getClass()))
90            throw new IllegalStateException(_LOG.getMessage(
91              "PROVIDER_NOT_RETURN_IMPLEMENTING_OBJECT", new Object[]{from, serviceClass.getName()}));
92  
93          return o;
94        }
95      }
96  
97      if (serviceClass.isAssignableFrom(from.getClass()))
98        return (T) from;
99  
100     return null;
101   }
102 
103   /**
104    * A convenience for retrieving a service from the current RenderKit.
105    */
106   static public <T> T getRenderKitService(FacesContext context,
107                                           Class<T> serviceClass)
108   {
109     // Provide a better exception than an NPE from inside of
110     // Service.getService().
111     RenderKit rk = context.getRenderKit();
112     if (rk == null)
113       throw new NullPointerException(_LOG.getMessage(
114         "OBTAIN_NULL_RENDERKIT_WHILE_GETTING_SERVICE", serviceClass.getName()));
115  
116 
117     return getService(rk, serviceClass);
118   }
119   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
120     Service.class);
121 }