001: /*
002: * Copyright 2007 Tim Peierls
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.guice;
017:
018: import java.util.Collection;
019: import java.util.Map;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023: import org.directwebremoting.dwrp.DefaultConverterManager;
024: import org.directwebremoting.extend.Converter;
025: import org.directwebremoting.extend.ConverterManager;
026: import org.directwebremoting.extend.InboundContext;
027: import org.directwebremoting.extend.InboundVariable;
028: import org.directwebremoting.extend.MarshallException;
029: import org.directwebremoting.extend.OutboundContext;
030: import org.directwebremoting.extend.OutboundVariable;
031: import org.directwebremoting.extend.TypeHintContext;
032:
033: import com.google.inject.Injector;
034: import com.google.inject.Key;
035: import com.google.inject.Provider;
036:
037: import static org.directwebremoting.guice.DwrGuiceUtil.getInjector;
038:
039: /**
040: * Extends an existing converter manager with an injected list of converters
041: * specified at Guice bind-time. Only to be used in conjunction with
042: * {@link DwrGuiceServlet}.
043: * @author Tim Peierls [tim at peierls dot net]
044: */
045: public class InternalConverterManager implements ConverterManager {
046: /**
047: * Retrieves an underlying converter manager from thread-local state
048: * to which this class delegates {@link ConverterManager} calls.
049: */
050: public InternalConverterManager() {
051: this .converterManager = getConverterManager();
052: addConverters();
053: }
054:
055: /* (non-Javadoc)
056: * @see org.directwebremoting.extend.ConverterManager#addConverterType(java.lang.String, java.lang.String)
057: */
058: public void addConverterType(String id, String className) {
059: converterManager.addConverterType(id, className);
060: }
061:
062: /* (non-Javadoc)
063: * @see org.directwebremoting.extend.ConverterManager#addConverter(java.lang.String, java.lang.String, java.util.Map)
064: */
065: public void addConverter(String match, String type,
066: Map<String, String> params)
067: throws IllegalArgumentException, InstantiationException,
068: IllegalAccessException {
069: converterManager.addConverter(match, type, params);
070: }
071:
072: /* (non-Javadoc)
073: * @see org.directwebremoting.extend.ConverterManager#addConverter(java.lang.String, org.directwebremoting.extend.Converter)
074: */
075: public void addConverter(String match, Converter converter)
076: throws IllegalArgumentException {
077: converterManager.addConverter(match, converter);
078: }
079:
080: /* (non-Javadoc)
081: * @see org.directwebremoting.extend.ConverterManager#getConverterMatchStrings()
082: */
083: public Collection<String> getConverterMatchStrings() {
084: return converterManager.getConverterMatchStrings();
085: }
086:
087: /* (non-Javadoc)
088: * @see org.directwebremoting.extend.ConverterManager#getConverterByMatchString(java.lang.String)
089: */
090: public Converter getConverterByMatchString(String match) {
091: return converterManager.getConverterByMatchString(match);
092: }
093:
094: /* (non-Javadoc)
095: * @see org.directwebremoting.extend.ConverterManager#isConvertable(java.lang.Class)
096: */
097: public boolean isConvertable(Class<?> paramType) {
098: return converterManager.isConvertable(paramType);
099: }
100:
101: /* (non-Javadoc)
102: * @see org.directwebremoting.extend.ConverterManager#convertInbound(java.lang.Class, org.directwebremoting.extend.InboundVariable, org.directwebremoting.extend.InboundContext, org.directwebremoting.extend.TypeHintContext)
103: */
104: public Object convertInbound(Class<?> paramType,
105: InboundVariable iv, InboundContext inctx,
106: TypeHintContext incc) throws MarshallException {
107: return converterManager.convertInbound(paramType, iv, inctx,
108: incc);
109: }
110:
111: /* (non-Javadoc)
112: * @see org.directwebremoting.extend.ConverterManager#convertOutbound(java.lang.Object, org.directwebremoting.extend.OutboundContext)
113: */
114: public OutboundVariable convertOutbound(Object object,
115: OutboundContext outctx) throws MarshallException {
116: return converterManager.convertOutbound(object, outctx);
117: }
118:
119: /* (non-Javadoc)
120: * @see org.directwebremoting.extend.ConverterManager#setExtraTypeInfo(org.directwebremoting.extend.TypeHintContext, java.lang.Class)
121: */
122: public void setExtraTypeInfo(TypeHintContext thc, Class<?> type) {
123: converterManager.setExtraTypeInfo(thc, type);
124: }
125:
126: /* (non-Javadoc)
127: * @see org.directwebremoting.extend.ConverterManager#getExtraTypeInfo(org.directwebremoting.extend.TypeHintContext)
128: */
129: public Class<?> getExtraTypeInfo(TypeHintContext thc) {
130: return converterManager.getExtraTypeInfo(thc);
131: }
132:
133: /* (non-Javadoc)
134: * @see org.directwebremoting.extend.ConverterManager#setConverters(java.util.Map)
135: */
136: public void setConverters(Map<String, Converter> converters) {
137: converterManager.setConverters(converters);
138: }
139:
140: /**
141: *
142: */
143: private final ConverterManager converterManager;
144:
145: @SuppressWarnings("unchecked")
146: private void addConverters() {
147: Injector injector = getInjector();
148: for (Key<?> key : injector.getBindings().keySet()) {
149: Class<?> atype = key.getAnnotationType();
150: if (atype != null
151: && Converting.class.isAssignableFrom(atype)) {
152: Converting ann = Converting.class.cast(key
153: .getAnnotation());
154:
155: String match = ann.match();
156: Class<?> type = ann.type();
157: Class<?> impl = ann.impl();
158:
159: if ("".equals(match)) {
160: // Use the type name as a match string
161: match = type.getName();
162: }
163:
164: Provider<Converter> provider = null;
165: Class<?> cvtType;
166:
167: if (impl.equals(Void.class)) {
168: // No impl specified, so there should be a Converter
169: // for this key.
170: provider = injector
171: .getProvider((Key<Converter>) key);
172: cvtType = type;
173: } else {
174: // Impl class specified, so the Converter for key is
175: // bogus (the injected constructor InternalConverter
176: // is just to keep Guice happy); see the two-arg
177: // bindConversion method in AbstractDwrModule.
178:
179: try {
180: // First try looking for a Converter for impl in the bindings.
181: Key<Converter> ikey = Key.get(Converter.class,
182: new ConvertingImpl(impl));
183: provider = injector.getProvider(ikey);
184: } catch (RuntimeException e) {
185: // Ignore any trouble we have looking things up.
186: }
187:
188: if (provider == null) {
189: // It wasn't in the bindings, so use a Provider that
190: // looks in the underlying ConverterManager.
191: final String implMatch = impl.getName();
192: provider = new Provider<Converter>() {
193: public Converter get() {
194: return getConverterByMatchString(implMatch);
195: }
196: };
197: }
198:
199: cvtType = impl;
200: }
201: addConverter(match, new InternalConverter(cvtType,
202: provider));
203: }
204: }
205: }
206:
207: /**
208: * Stores a type name in a thread-local variable for later retrieval by
209: * {@code getConverterManager}.
210: */
211: static void setTypeName(String name) {
212: typeName.set(name);
213: }
214:
215: /**
216: *
217: */
218: private static ConverterManager getConverterManager() {
219: String name = typeName.get();
220: try {
221: @SuppressWarnings("unchecked")
222: Class<? extends ConverterManager> cls = (Class<? extends ConverterManager>) Class
223: .forName(name);
224: return cls.newInstance();
225: } catch (Exception e) {
226: if (name != null && !"".equals(name)) {
227: log.warn("Couldn't make ConverterManager from type: "
228: + name);
229: }
230: return new DefaultConverterManager();
231: }
232: }
233:
234: /**
235: * Place to stash a type name for retrieval in same thread.
236: */
237: private static final ThreadLocal<String> typeName = new ThreadLocal<String>();
238:
239: /**
240: * The log stream
241: */
242: private static final Log log = LogFactory
243: .getLog(InternalConverterManager.class);
244: }
|