View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.cubby.dxo.impl;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.seasar.extension.dxo.converter.ConversionContext;
24  import org.seasar.extension.dxo.converter.Converter;
25  import org.seasar.extension.dxo.converter.impl.ConverterFactoryImpl;
26  import org.seasar.framework.container.ComponentDef;
27  import org.seasar.framework.container.S2Container;
28  import org.seasar.framework.container.factory.S2ContainerFactory;
29  import org.seasar.framework.log.Logger;
30  import org.seasar.framework.util.DisposableUtil;
31  import org.seasar.framework.util.ResourceUtil;
32  
33  /**
34   * リクエストのパラメータとアクションのプロパティとの変換に使用する{@link org.seasar.extension.dxo.converter.Converter コンバータ}のファクトリクラスです。
35   * 
36   * @author baba
37   * @since 1.0.0
38   */
39  public class RequestParameterConverterFactoryImpl extends ConverterFactoryImpl {
40  
41  	/** ロガー。 */
42  	private static final Logger logger = Logger
43  			.getLogger(RequestParameterConverterFactoryImpl.class);
44  
45  	/** 空のコンバータの配列。 */
46  	private static final Converter[] EMPTY_CONVERTER_ARRAY = new Converter[0];
47  
48  	/** コンバータのラッパのキャッシュ。 */
49  	private static final Map<Converter, Converter> wrapperCache = new HashMap<Converter, Converter>();
50  
51  	/** コンバータが定義されたコンテナのパス。 */
52  	private final List<String> converterContainerPaths = new ArrayList<String>();
53  
54  	/** コンバータが定義されたコンテナ。 */
55  	private final List<S2Container> containers = new ArrayList<S2Container>();
56  
57  	/** アプリケーションで定義したコンバータを使用するかどうかを示します。 */
58  	private boolean includeApplicationConverters = true;
59  
60  	/** 初期化されたかどうかを示します。 */
61  	private boolean initialized = false;
62  
63  	/**
64  	 * コンバータが定義されたコンテナのパスを追加します。
65  	 * 
66  	 * @param converterContainerPath
67  	 *            コンバータが定義されたコンテナのパス
68  	 */
69  	public void addConverterContainerPath(final String converterContainerPath) {
70  		this.converterContainerPaths.add(converterContainerPath);
71  	}
72  
73  	/**
74  	 * アプリケーションで定義したコンバータを使用するかどうかを設定します。
75  	 * 
76  	 * @param includeApplicationConverters
77  	 *            アプリケーションで定義したコンバータを使用する場合は <code>true</code>、そうでない場合は
78  	 *            <code>false</code>
79  	 */
80  	public void setIncludeApplicationConverters(
81  			final boolean includeApplicationConverters) {
82  		this.includeApplicationConverters = includeApplicationConverters;
83  	}
84  
85  	/**
86  	 * {@inheritDoc}
87  	 */
88  	@Override
89  	public void initialize() {
90  		if (initialized) {
91  			return;
92  		}
93  
94  		super.initialize();
95  
96  		final Map<Class<? extends Converter>, Converter> converterMap = new HashMap<Class<? extends Converter>, Converter>();
97  		for (final String path : this.converterContainerPaths) {
98  			if (ResourceUtil.isExist(path)) {
99  				if (logger.isDebugEnabled()) {
100 					logger.log("DCUB0011", new Object[] { path });
101 				}
102 				final S2Container container = S2ContainerFactory.create(path);
103 				containers.add(container);
104 				for (final ComponentDef componentDef : container
105 						.findAllComponentDefs(Converter.class)) {
106 					final Converter converter = (Converter) componentDef
107 							.getComponent();
108 					converterMap.put(converter.getClass(), converter);
109 					if (logger.isDebugEnabled()) {
110 						logger.log("DCUB0010", new Object[] { converter });
111 					}
112 				}
113 				if (logger.isDebugEnabled()) {
114 					logger
115 							.log("DCUB0012",
116 									new Object[] { container.getPath() });
117 				}
118 			}
119 		}
120 
121 		if (includeApplicationConverters) {
122 			final List<Converter> converterList = new ArrayList<Converter>(
123 					converterMap.values());
124 			if (logger.isDebugEnabled()) {
125 				logger.log("DCUB0013", null);
126 			}
127 			for (final Converter converter : converters) {
128 				if (!converterMap.containsKey(converter.getClass())) {
129 					converterList.add(converter);
130 					if (logger.isDebugEnabled()) {
131 						logger.log("DCUB0010", new Object[] { converter });
132 					}
133 				}
134 			}
135 			if (logger.isDebugEnabled()) {
136 				logger.log("DCUB0014", null);
137 			}
138 			converters = converterList.toArray(EMPTY_CONVERTER_ARRAY);
139 		} else {
140 			converters = converterMap.values().toArray(EMPTY_CONVERTER_ARRAY);
141 		}
142 
143 		DisposableUtil.add(this);
144 		initialized = true;
145 	}
146 
147 	/**
148 	 * {@inheritDoc}
149 	 */
150 	@Override
151 	public void dispose() {
152 		wrapperCache.clear();
153 		for (final S2Container container : this.containers) {
154 			container.destroy();
155 		}
156 		containers.clear();
157 		super.dispose();
158 		initialized = false;
159 	}
160 
161 	/**
162 	 * {@inheritDoc}
163 	 * <p>
164 	 * ここで生成されるコンバータは、{@link Converter#convert(Object, Class, ConversionContext)}の実行時に例外が発生した場合は
165 	 * <code>null</code> を返すようにラップされます。
166 	 * </p>
167 	 */
168 	@Override
169 	@SuppressWarnings("unchecked")
170 	public Converter getConverter(final Class sourceClass, final Class destClass) {
171 		initialize();
172 		final Converter converter = super.getConverter(sourceClass, destClass);
173 		final Converter wrapper;
174 		if (wrapperCache.containsKey(converter)) {
175 			wrapper = wrapperCache.get(converter);
176 		} else {
177 			wrapper = new DisregardExceptionConverterWrapper(converter);
178 			wrapperCache.put(converter, wrapper);
179 		}
180 		return wrapper;
181 	}
182 
183 	/**
184 	 * 変換時の例外を無視するように{@link Converter}をラップするクラスです。
185 	 * 
186 	 * @author baba
187 	 */
188 	private static class DisregardExceptionConverterWrapper implements
189 			Converter {
190 
191 		/** ラップするコンバータ。 */
192 		private final Converter converter;
193 
194 		/**
195 		 * インスタンス化します。
196 		 * 
197 		 * @param converter
198 		 *            ラップするコンバータ
199 		 */
200 		private DisregardExceptionConverterWrapper(final Converter converter) {
201 			this.converter = converter;
202 		}
203 
204 		/**
205 		 * {@inheritDoc}
206 		 * <p>
207 		 * 変換時に例外が発生した場合は <code>null</code> を返します。
208 		 * </p>
209 		 */
210 		@SuppressWarnings("unchecked")
211 		public Object convert(final Object source, final Class destClass,
212 				final ConversionContext context) {
213 			try {
214 				return converter.convert(source, destClass, context);
215 			} catch (final Exception e) {
216 				return null;
217 			}
218 		}
219 
220 		/**
221 		 * {@inheritDoc}
222 		 * 
223 		 * @see #convert(Object, Class, ConversionContext)
224 		 */
225 		public void convert(final Object source, final Object dest,
226 				final ConversionContext context) {
227 			converter.convert(source, dest, context);
228 		}
229 
230 		/**
231 		 * {@inheritDoc}
232 		 */
233 		@SuppressWarnings("unchecked")
234 		public Class getDestClass() {
235 			return converter.getDestClass();
236 		}
237 
238 		/**
239 		 * {@inheritDoc}
240 		 */
241 		@SuppressWarnings("unchecked")
242 		public Class[] getSourceClasses() {
243 			return converter.getSourceClasses();
244 		}
245 
246 	}
247 
248 }