001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.widget.google.provider;
023:
024: import org.jboss.portal.common.xml.XMLTools;
025: import org.jboss.portal.common.i18n.LocalizedString;
026: import org.jboss.portal.common.net.URLTools;
027: import org.jboss.portal.widget.exceptions.WidgetException;
028: import org.jboss.portal.widget.exceptions.WidgetFetchException;
029: import org.jboss.portal.widget.exceptions.WidgetMetaDataParseException;
030: import org.jboss.portal.widget.exceptions.WidgetNotSupportedException;
031: import org.jboss.portal.widget.google.type.DataType;
032: import org.jboss.portal.widget.google.type.StringType;
033: import org.jboss.portal.widget.google.type.LocationType;
034: import org.jboss.portal.widget.google.type.HiddenType;
035: import org.jboss.portal.widget.google.type.BoolType;
036: import org.jboss.portal.widget.google.type.ListType;
037: import org.jboss.portal.widget.google.type.EnumType;
038: import org.jboss.portal.widget.google.info.GGPreferenceInfo;
039: import org.jboss.portal.widget.google.info.GGPreferencesInfo;
040: import org.jboss.portal.widget.google.info.GGWidgetInfo;
041: import org.w3c.dom.Document;
042: import org.w3c.dom.Element;
043: import org.w3c.dom.NodeList;
044: import org.w3c.dom.Node;
045:
046: import javax.xml.parsers.DocumentBuilderFactory;
047: import javax.xml.parsers.DocumentBuilder;
048:
049: import java.net.MalformedURLException;
050: import java.net.URL;
051: import java.text.NumberFormat;
052: import java.util.Iterator;
053: import java.util.Locale;
054: import java.util.Collection;
055: import java.util.ArrayList;
056: import java.util.Map;
057: import java.util.HashMap;
058: import java.io.ByteArrayInputStream;
059:
060: /**
061: * Build widget meta data from its URL.
062: *
063: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
064: * @version $Revision: 9212 $
065: */
066: public class GGWidgetInfoBuilder {
067: /** . */
068: private static final org.jboss.logging.Logger log = org.jboss.logging.Logger
069: .getLogger(GGWidgetInfoBuilder.class);
070:
071: /** . */
072: private final URL url;
073:
074: public GGWidgetInfoBuilder(URL url) {
075: if (url == null) {
076: throw new IllegalArgumentException("No null URL");
077: }
078:
079: //
080: this .url = url;
081: }
082:
083: public URL getURL() {
084: return url;
085: }
086:
087: /**
088: * Build the widget info from the url or throws an exception if it is not possible.
089: *
090: * @return the widget info
091: * @throws Exception
092: */
093: public GGWidgetInfo create() throws WidgetException,
094: MalformedURLException {
095: long millis = System.currentTimeMillis();
096: byte[] bytes = obtainWidget(url);
097: // No response was obtained
098: if (bytes == null) {
099: throw new WidgetFetchException(
100: "Could not retreive widget data.");
101: }
102:
103: //
104: DocumentBuilderFactory factory;
105: DocumentBuilder builder;
106: Document doc;
107: try {
108: factory = XMLTools.getDocumentBuilderFactory();
109: builder = factory.newDocumentBuilder();
110: doc = builder.parse(new ByteArrayInputStream(bytes));
111: } catch (Exception e) {
112: throw new WidgetMetaDataParseException(
113: "Could not parse widget document.");
114: }
115: //
116: Element moduleElt = doc.getDocumentElement();
117:
118: Map messagesBundle = new HashMap();
119:
120: //first process locale bundles
121: Iterator modulePrefsEltIterator = XMLTools.getChildrenIterator(
122: moduleElt, "ModulePrefs");
123: if (modulePrefsEltIterator.hasNext()) {
124: Element modulePrefsElt = (Element) modulePrefsEltIterator
125: .next();
126:
127: Iterator localeEltIterator = XMLTools.getChildrenIterator(
128: modulePrefsElt, "Locale");
129:
130: Map messages = new HashMap();
131:
132: while (localeEltIterator.hasNext()) {
133: Element localeElt = (Element) localeEltIterator.next();
134:
135: String langAttr = localeElt.getAttribute("lang");
136: String countryAttr = localeElt.getAttribute("country");
137: String messagesAttr = localeElt
138: .getAttribute("messages");
139:
140: //as portal spec defines fallback to EN we'll use it for all_ALL gg bundle
141: if (langAttr == null || langAttr.length() == 0) {
142: langAttr = "en";
143: }
144:
145: Locale locale;
146: if (countryAttr == null || countryAttr.length() == 0) {
147: locale = new Locale(langAttr);
148: } else {
149: locale = new Locale(langAttr, countryAttr);
150: }
151:
152: URL bundleURL = new URL(url, messagesAttr);
153:
154: byte[] bundleBytes = obtainLocaleBundle(bundleURL);
155:
156: //if no response obtained - ignore this bundle
157: if (bundleBytes == null) {
158: continue;
159: }
160:
161: DocumentBuilder bundleDocBuilder;
162: Document bundleDoc;
163: try {
164: bundleDocBuilder = factory.newDocumentBuilder();
165: bundleDoc = bundleDocBuilder
166: .parse(new ByteArrayInputStream(bundleBytes));
167: } catch (Exception e) {
168: throw new WidgetMetaDataParseException(
169: "Could not parse bundles.");
170: }
171:
172: Element messagebundleElt = bundleDoc
173: .getDocumentElement();
174: Iterator messagesEltIterator = XMLTools
175: .getChildrenIterator(messagebundleElt, "msg");
176:
177: while (messagesEltIterator.hasNext()) {
178: Element msgElt = (Element) messagesEltIterator
179: .next();
180:
181: String name = msgElt.getAttribute("name");
182:
183: StringBuffer value = new StringBuffer();
184:
185: //create value from the tag content
186: NodeList nodes = msgElt.getChildNodes();
187: for (int i = 0; i < nodes.getLength(); i++) {
188: Node n = nodes.item(i);
189:
190: if (n.getNodeType() == Element.TEXT_NODE) {
191: value.append(n.getNodeValue());
192: }
193: }
194:
195: Map entries;
196: if (!messages.containsKey(name)) {
197: entries = new HashMap();
198: messages.put(name, entries);
199: } else {
200: entries = (Map) messages.get(name);
201: }
202:
203: entries.put(locale, value.toString());
204: }
205: }
206:
207: //Reiterate whole bundle to store LocalizedString values;
208: for (Iterator iterator = messages.keySet().iterator(); iterator
209: .hasNext();) {
210: String name = (String) iterator.next();
211: Map entries = (Map) messages.get(name);
212:
213: messagesBundle.put(name, new LocalizedString(entries,
214: Locale.ENGLISH));
215: }
216: } else {
217: throw new WidgetMetaDataParseException(
218: "Could not parse widget meta data.");
219: }
220:
221: //
222: Collection tmp = null;
223: Iterator userPrefsEltIterator = XMLTools.getChildrenIterator(
224: moduleElt, "UserPref");
225: while (userPrefsEltIterator.hasNext()) {
226: Element userPref = (Element) userPrefsEltIterator.next();
227: String nameAttr = userPref.getAttribute("name");
228: String displayNameAttr = userPref
229: .getAttribute("display_name");
230: String urlParamAttr = userPref.getAttribute("urlparam");
231: String dataTypeAttr = userPref.getAttribute("datatype");
232: String requiredAttr = userPref.getAttribute("required");
233: String defaultValueAttr = userPref
234: .getAttribute("default_value");
235:
236: // We don't support that for now
237: if (urlParamAttr.length() > 0) {
238: throw new WidgetNotSupportedException(
239: "urlparam not supported yet.");
240: }
241:
242: // String is default type when not specified
243: DataType dataType = StringType.getInstance();
244: if (dataTypeAttr.length() > 0) {
245: int dataTypeOrdinal = DataType
246: .parseDataTypeLiteral(dataTypeAttr);
247: switch (dataTypeOrdinal) {
248: case DataType.HIDDEN:
249: dataType = HiddenType.getInstance();
250: break;
251: case DataType.BOOL:
252: dataType = BoolType.getInstance();
253: break;
254: case DataType.STRING:
255: dataType = StringType.getInstance();
256: break;
257: case DataType.LIST:
258: dataType = ListType.getInstance();
259: break;
260: case DataType.ENUM:
261: Collection values = new ArrayList();
262: for (Iterator i = XMLTools.getChildrenIterator(
263: userPref, "EnumValue"); i.hasNext();) {
264: Element enumValueElt = (Element) i.next();
265: String valueAttr = enumValueElt
266: .getAttribute("value");
267: String displayValueAttr = enumValueElt
268: .getAttribute("display_value");
269:
270: EnumType.Value value = new EnumType.Value(
271: valueAttr, resolveLocalizedValue(
272: displayValueAttr,
273: messagesBundle));
274: values.add(value);
275: }
276: dataType = new EnumType(values);
277: break;
278: case DataType.LOCATION:
279: dataType = LocationType.getInstance();
280: break;
281: }
282: }
283:
284: //
285: GGPreferenceInfo prefInfo = new GGPreferenceInfo(nameAttr,
286: dataType, resolveLocalizedValue(displayNameAttr,
287: messagesBundle),
288: requiredAttr.length() > 0 ? Boolean.valueOf(
289: requiredAttr).booleanValue() : false,
290: defaultValueAttr.length() > 0 ? defaultValueAttr
291: : null);
292:
293: //
294: if (tmp == null) {
295: tmp = new ArrayList();
296: }
297: tmp.add(prefInfo);
298: }
299: GGPreferencesInfo prefsInfo = GGPreferencesInfo.EMPTY_PREFS;
300: if (tmp != null) {
301: prefsInfo = new GGPreferencesInfo(tmp);
302: }
303:
304: modulePrefsEltIterator = XMLTools.getChildrenIterator(
305: moduleElt, "ModulePrefs");
306: if (modulePrefsEltIterator.hasNext()) {
307: Element modulePrefsElt = (Element) modulePrefsEltIterator
308: .next();
309: String titleAttr = modulePrefsElt.getAttribute("title");
310: String directoryTitleAttr = modulePrefsElt
311: .getAttribute("directory_title");
312: String descriptionAttr = modulePrefsElt
313: .getAttribute("description");
314: String widthAttr = modulePrefsElt.getAttribute("width");
315: String heightAttr = modulePrefsElt.getAttribute("height");
316:
317: //
318: LocalizedString title = resolveLocalizedStringValue(
319: titleAttr, messagesBundle);
320: LocalizedString directoryTitle = resolveLocalizedStringValue(
321: directoryTitleAttr, messagesBundle);
322: LocalizedString description = resolveLocalizedStringValue(
323: descriptionAttr, messagesBundle);
324:
325: int width = (widthAttr != null && widthAttr.length() > 0) ? Integer
326: .parseInt(widthAttr)
327: : 320;
328: int height = (heightAttr != null && heightAttr.length() > 0) ? Integer
329: .parseInt(heightAttr)
330: : 200;
331: if (log.isDebugEnabled()) {
332: log
333: .debug("fetchting & building gadget: "
334: + url.toString()
335: + " took: "
336: + NumberFormat
337: .getInstance()
338: .format(
339: (System
340: .currentTimeMillis() - millis) / 1000.0));
341: }
342: return new GGWidgetInfo(title, directoryTitle, description,
343: width, height, prefsInfo);
344: } else {
345: throw new WidgetMetaDataParseException(
346: "Could parse widget meta data.");
347: }
348: }
349:
350: private LocalizedString resolveLocalizedStringValue(String value,
351: Map bundle) {
352: if (value != null) {
353: if (value.startsWith("__MSG_")) {
354: String name = value.substring("__MSG_".length(), value
355: .length() - 2);
356:
357: if (bundle.containsKey(name)) {
358: return (LocalizedString) bundle.get(name);
359: }
360: }
361:
362: return new LocalizedString(value, Locale.ENGLISH);
363: }
364: return null;
365:
366: }
367:
368: private String resolveLocalizedValue(String value, Map bundle) {
369: LocalizedString out = resolveLocalizedStringValue(value, bundle);
370:
371: if (out != null && !"".equals(out.getDefaultString())) {
372: return out.getDefaultString();
373: }
374: return null;
375: }
376:
377: /**
378: * needed for testing
379: */
380: protected byte[] obtainWidget(URL url)
381: throws IllegalArgumentException {
382: return obtainURL(url);
383: }
384:
385: /**
386: * needed for testing
387: */
388: protected byte[] obtainLocaleBundle(URL url)
389: throws IllegalArgumentException {
390: return obtainURL(url);
391: }
392:
393: private byte[] obtainURL(URL url) throws IllegalArgumentException {
394: return URLTools.getContent(url, 5000, 5000);
395: }
396:
397: }
|