1 /*
2 * Copyright 2012 Olivier Godineau
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 * License for the specific language governing permissions and limitations under
12 * the License.
13 */
14 package olg.csv.bean.loader;
15
16 import java.util.Date;
17 import java.util.Locale;
18
19 import javax.xml.xpath.XPathConstants;
20 import javax.xml.xpath.XPathExpressionException;
21
22 import olg.csv.bean.formatter.Formatter;
23
24 import org.w3c.dom.Element;
25 import org.w3c.dom.Node;
26
27 /**
28 *
29 * Class dedicated to load a formatter {@link Formatter} from an XML element
30 * conformed to XML schema FormatterType specification. Each concret class shall
31 * have the responsibility to load a concrete Formatter class.
32 *
33 * <p>
34 * Class based on Chain of responsability pattern and used to chain concret
35 * Formatter Loaders.
36 * </p>
37 *
38 * @author Olivier Godineau
39 *
40 */
41 public abstract class AbstractFormatterLoader {
42 /**
43 * Singleton instance to use to load Formatter.
44 */
45 private static AbstractFormatterLoader instance = new DateFormatterLoader(new CustomFormatterLoader(null));
46
47 /**
48 * Returns singleton responsible of formatters loading.
49 *
50 * This is this instance you have to be used to load every type of
51 * formatters from XML element conformed to XML Schema FormatterType
52 * specification.
53 *
54 * @return the AbstractFormatter loader
55 */
56 public static AbstractFormatterLoader getInstance() {
57 return instance;
58 }
59
60 /**
61 * FormatterLoader successor as describe in Chain of responsability pattern.
62 */
63 protected AbstractFormatterLoader successor;
64
65 /**
66 * This Xpath expression allows to identify xml node which describe the
67 * corresponding concret formatter under formatterType node.
68 */
69 protected String xPathExpression;
70
71 /**
72 * Returns a concret formatter identified from the given XML element.
73 *
74 * @param element
75 * XML node corresponding to correspondant to XML FormatterType
76 * as described in our XML schema.
77 * @return a concret formatter or <code>null</code> if the given element
78 * doesn't match the concret formatter type this loader has
79 * responsability and doesn't match any successor
80 * @throws XPathExpressionException
81 * on invalid XPathExpression
82 * @throws LoadException
83 * on Error occurs during loading
84 */
85 public final Formatter<?> getFormatter(Element element) throws XPathExpressionException, LoadException {
86 Formatter<?> retour = null;
87
88 if (element != null) {
89 Node node = (Node) Util.evaluerDOM(element, xPathExpression, XPathConstants.NODE);
90 if (node != null) { // NOPMD by olivier on 01/02/12 00:43
91 retour = getConcreteFormatter((Element) node);
92 } else {
93 if (successor != null) {
94 retour = successor.getFormatter(element);
95 }
96 }
97 }
98 return retour;
99 }
100
101 /**
102 *
103 * Returns a concret formatter.
104 *
105 * @param node
106 * XML Element corresponding to the XPath expression. From this
107 * element a concret formatter this loader should return will be
108 * extracted
109 *
110 * @return a concret formatter this loader has responsability or
111 * <code>null</code> if the given node doesn't match the type this
112 * loader should return
113 * @throws XPathExpressionException
114 * on invalid XPathExpression
115 * @throws LoadException
116 * on Error occurs during loading
117 * @see #xPathExpression
118 */
119 protected abstract Formatter<?> getConcreteFormatter(Element node) throws XPathExpressionException, LoadException;
120
121 /**
122 *
123 * @param xPathExpression
124 * XPath expression that allows to identify the concret formatter
125 * under the XML FormatterType node
126 * @param successor
127 * following concret loader in the chain of responsability
128 *
129 */
130 protected AbstractFormatterLoader(String xPathExpression, AbstractFormatterLoader successor) {
131 super();
132 this.successor = successor;
133 this.xPathExpression = xPathExpression;
134 }
135
136 /**
137 * Class responsible of DateFormatter loading.
138 *
139 * @see Formatter#getDateFormatter(String, Locale)
140 */
141 private static class DateFormatterLoader extends AbstractFormatterLoader {
142
143 /**
144 *
145 * @param successor
146 * the next loader in the formatter loaders chain.
147 */
148 protected DateFormatterLoader(AbstractFormatterLoader successor) {
149 super("date", successor);
150
151 }
152
153 @Override
154 protected Formatter<? extends Date> getConcreteFormatter(Element node) throws XPathExpressionException,
155 LoadException {
156 String loc = node.getAttribute("locale");
157 Locale locale = Util.getLocale(loc);
158 if (!"".equals(loc) && locale == null) {
159 throw new LoadException("Locale based on expression[" + loc + "] is not available ");
160 }
161
162 return Formatter.getDateFormatter(node.getAttribute("format"), locale);
163 }
164
165 }
166
167 /**
168 * Class responsible of CustomFormatter loading.
169 *
170 * @see CustomLoader
171 */
172 private static class CustomFormatterLoader extends AbstractFormatterLoader {
173
174 /**
175 *
176 * @param successor
177 * the next loader in the formatter loaders chain.
178 */
179 protected CustomFormatterLoader(AbstractFormatterLoader successor) {
180 super("custom", successor);
181
182 }
183
184 @Override
185 protected Formatter<?> getConcreteFormatter(Element node) throws XPathExpressionException, LoadException {
186 Object object = CustomLoader.getBean(node);
187 if (!(object instanceof Formatter)) {
188 throw new LoadException(object.getClass() + " must extend " + Formatter.class);
189 }
190
191 return (Formatter<?>) object;
192 }
193 }
194 }