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 }