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 }