Author: julien(a)jboss.com
Date: 2007-03-09 14:48:05 -0500 (Fri, 09 Mar 2007)
New Revision: 6616
Added:
trunk/widget/src/main/org/jboss/portal/widget/google/provider/
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGProvider.java
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQuery.java
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResult.java
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResultBuilder.java
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGWidgetBuilder.java
Removed:
trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetBatch.java
trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetFactory.java
trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetProvider.java
Modified:
trunk/widget/src/main/org/jboss/portal/widget/WidgetPortlet.java
trunk/widget/src/main/org/jboss/portal/widget/google/GGPreferenceInfo.java
Log:
- added query support for widget provider
- rewrote the widget fetching part in order to handle queries
Modified: trunk/widget/src/main/org/jboss/portal/widget/WidgetPortlet.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/WidgetPortlet.java 2007-03-09 08:05:41
UTC (rev 6615)
+++ trunk/widget/src/main/org/jboss/portal/widget/WidgetPortlet.java 2007-03-09 19:48:05
UTC (rev 6616)
@@ -22,9 +22,10 @@
******************************************************************************/
package org.jboss.portal.widget;
-import org.jboss.portal.widget.google.GGWidgetProvider;
import org.jboss.portal.widget.google.GGWidget;
import org.jboss.portal.widget.google.GGPreferenceInfo;
+import org.jboss.portal.widget.google.provider.GGProvider;
+import org.jboss.portal.widget.google.provider.GGQueryResult;
import org.jboss.portal.widget.google.type.DataType;
import javax.portlet.GenericPortlet;
@@ -48,7 +49,7 @@
{
/** . */
- private GGWidgetProvider provider = new GGWidgetProvider();
+ private GGProvider provider = new GGProvider();
public void init() throws PortletException
{
@@ -88,7 +89,7 @@
if ("select".equals(op))
{
String uri = req.getParameter("uri");
- GGWidget widget = (GGWidget)provider.getWidget(uri);
+ GGWidget widget = provider.getWidget(uri);
if (widget != null)
{
PortletURL selectURL = resp.createActionURL();
@@ -118,13 +119,12 @@
}
//
- Collection widgets = provider.getKeys();
+ GGQueryResult result = provider.search(GGProvider.INITIAL_QUERY);
writer.print("<ul>");
int size = 0;
- for (Iterator i = widgets.iterator();i.hasNext() && size < 9;size++)
+ for (Iterator i = result.getWidgets();i.hasNext() && size < 9;size++)
{
- String key = (String)i.next();
- Widget widget = provider.getWidget(key);
+ Widget widget = (Widget)i.next();
if (widget != null)
{
PortletURL url = resp.createRenderURL();
Modified: trunk/widget/src/main/org/jboss/portal/widget/google/GGPreferenceInfo.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/GGPreferenceInfo.java 2007-03-09
08:05:41 UTC (rev 6615)
+++ trunk/widget/src/main/org/jboss/portal/widget/google/GGPreferenceInfo.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -46,7 +46,7 @@
/** . */
private final String defaultValue;
- protected GGPreferenceInfo(String name, DataType type, String displayName, boolean
required, String defaultValue)
+ public GGPreferenceInfo(String name, DataType type, String displayName, boolean
required, String defaultValue)
{
this.name = name;
this.type = type;
Deleted: trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetBatch.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetBatch.java 2007-03-09
08:05:41 UTC (rev 6615)
+++ trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetBatch.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -1,64 +0,0 @@
-/******************************************************************************
- * JBoss, a division of Red Hat *
- * Copyright 2006, Red Hat Middleware, LLC, and individual *
- * contributors as indicated by the @authors tag. See the *
- * copyright.txt in the distribution for a full listing of *
- * individual contributors. *
- * *
- * This is free software; you can redistribute it and/or modify it *
- * under the terms of the GNU Lesser General Public License as *
- * published by the Free Software Foundation; either version 2.1 of *
- * the License, or (at your option) any later version. *
- * *
- * This software is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
- * Lesser General Public License for more details. *
- * *
- * You should have received a copy of the GNU Lesser General Public *
- * License along with this software; if not, write to the Free *
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
- ******************************************************************************/
-package org.jboss.portal.widget.google;
-
-import org.apache.log4j.Logger;
-import org.jboss.portal.common.concurrent.loader.ObjectBatch;
-import org.jboss.portal.common.concurrent.loader.LoadingPolicy;
-import org.jboss.portal.common.concurrent.loader.LoaderContext;
-
-/**
- * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
- * @version $Revision: 1.1 $
- */
-public class GGWidgetBatch
-{
-
- /** . */
- private static final Logger log = Logger.getLogger(GGWidgetBatch.class);
-
- /** . */
- private final ObjectBatch batch;
-
- public GGWidgetBatch(GGWidgetFactory[] factories)
- {
- this.batch = new ObjectBatch(factories, LoadingPolicy.LOAD_ALL_ASYNC);
- }
-
- public int getSize()
- {
- return batch.getSize();
- }
-
- public GGWidget getWidget(LoaderContext loaderContext, int index)
- {
- try
- {
- return (GGWidget)batch.getObject(loaderContext, index);
- }
- catch (InterruptedException e)
- {
- return null;
- }
- }
-}
Deleted: trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetFactory.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetFactory.java 2007-03-09
08:05:41 UTC (rev 6615)
+++ trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetFactory.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -1,200 +0,0 @@
-/******************************************************************************
- * JBoss, a division of Red Hat *
- * Copyright 2006, Red Hat Middleware, LLC, and individual *
- * contributors as indicated by the @authors tag. See the *
- * copyright.txt in the distribution for a full listing of *
- * individual contributors. *
- * *
- * This is free software; you can redistribute it and/or modify it *
- * under the terms of the GNU Lesser General Public License as *
- * published by the Free Software Foundation; either version 2.1 of *
- * the License, or (at your option) any later version. *
- * *
- * This software is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
- * Lesser General Public License for more details. *
- * *
- * You should have received a copy of the GNU Lesser General Public *
- * License along with this software; if not, write to the Free *
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
- ******************************************************************************/
-package org.jboss.portal.widget.google;
-
-import org.jboss.portal.common.util.XML;
-import org.jboss.portal.common.util.LocalizedString;
-import org.jboss.portal.common.util.URLTools;
-import org.jboss.portal.common.concurrent.loader.ObjectLoader;
-import org.jboss.portal.widget.google.type.DataType;
-import org.jboss.portal.widget.google.type.StringType;
-import org.jboss.portal.widget.google.type.LocationType;
-import org.jboss.portal.widget.google.type.HiddenType;
-import org.jboss.portal.widget.google.type.BoolType;
-import org.jboss.portal.widget.google.type.ListType;
-import org.jboss.portal.widget.google.type.EnumType;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.DocumentBuilder;
-import java.net.URL;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Collection;
-import java.util.ArrayList;
-import java.io.ByteArrayInputStream;
-
-/**
- * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
- * @version $Revision: 1.1 $
- */
-public class GGWidgetFactory implements ObjectLoader
-{
-
- /** . */
- private final URL url;
-
- public GGWidgetFactory(URL url)
- {
- if (url == null)
- {
- throw new IllegalArgumentException("No null URL");
- }
- this.url = url;
- }
-
- public URL getURL()
- {
- return url;
- }
-
-
- public Object load()
- {
- try
- {
- return create();
- }
- catch (Exception e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings |
File Templates.
-
- //
- return null;
- }
- }
-
- public GGWidget create() throws Exception
- {
- DocumentBuilderFactory factory = XML.getDocumentBuilderFactory();
- DocumentBuilder builder = factory.newDocumentBuilder();
- byte[] bytes = URLTools.performGET(url, 5000, 5000);
- if (bytes == null)
- {
- throw new Exception("Cannot retrieve document " + url);
- }
- Document doc = builder.parse(new ByteArrayInputStream(bytes));
- Element moduleElt = doc.getDocumentElement();
-
- //
- Collection tmp = null;
- Iterator userPrefsEltIterator = XML.getChildrenIterator(moduleElt,
"UserPref");
- while (userPrefsEltIterator.hasNext())
- {
- Element userPref = (Element)userPrefsEltIterator.next();
- String nameAttr = userPref.getAttribute("name");
- String displayNameAttr = userPref.getAttribute("displayName");
- String urlParamAttr = userPref.getAttribute("urlparam");
- String dataTypeAttr = userPref.getAttribute("datatype");
- String requiredAttr = userPref.getAttribute("required");
- String defaultValueAttr = userPref.getAttribute("default_value");
-
- // We don't support that for now
- if (urlParamAttr.length() > 0)
- {
- throw new Exception();
- }
-
- // String is default type when not specified
- DataType dataType = StringType.getInstance();
- if (dataTypeAttr.length() > 0)
- {
- int dataTypeOrdinal = DataType.parseDataTypeLiteral(dataTypeAttr);
- switch(dataTypeOrdinal)
- {
- case DataType.HIDDEN:
- dataType = HiddenType.getInstance();
- break;
- case DataType.BOOL:
- dataType = BoolType.getInstance();
- break;
- case DataType.STRING:
- dataType = StringType.getInstance();
- break;
- case DataType.LIST:
- dataType = ListType.getInstance();
- break;
- case DataType.ENUM:
- Collection values = new ArrayList();
- for (Iterator i = XML.getChildrenIterator(userPref,
"EnumValue");i.hasNext();)
- {
- Element enumValueElt = (Element)i.next();
- String valueAttr = enumValueElt.getAttribute("value");
- String displayValueAttr =
enumValueElt.getAttribute("display_value");
- EnumType.Value value = new EnumType.Value(valueAttr,
displayValueAttr.length() > 0 ? displayValueAttr : null);
- values.add(value);
- }
- dataType = new EnumType(values);
- break;
- case DataType.LOCATION:
- dataType = LocationType.getInstance();
- break;
- }
- }
-
- //
- GGPreferenceInfo prefInfo = new GGPreferenceInfo(
- nameAttr,
- dataType,
- displayNameAttr.length() > 0 ? displayNameAttr : null,
- requiredAttr.length() > 0 ? Boolean.valueOf(requiredAttr).booleanValue() :
false,
- defaultValueAttr.length() > 0 ? defaultValueAttr : null
- );
-
- //
- if (tmp == null)
- {
- tmp = new ArrayList();
- }
- tmp.add(prefInfo);
- }
- GGPreferencesInfo prefsInfo = GGPreferencesInfo.EMPTY_PREFS;
- if (tmp != null)
- {
- prefsInfo = new GGPreferencesInfo(tmp);
- }
-
- //
- Iterator modulePrefsEltIterator = XML.getChildrenIterator(moduleElt,
"ModulePrefs");
- if (modulePrefsEltIterator.hasNext())
- {
- Element modulePrefsElt = (Element)modulePrefsEltIterator.next();
- String titleAttr = modulePrefsElt.getAttribute("title");
- String descriptionAttr = modulePrefsElt.getAttribute("description");
- String widthAttr = modulePrefsElt.getAttribute("width");
- String heightAttr = modulePrefsElt.getAttribute("height");
-
- //
- LocalizedString title = titleAttr != null ? new LocalizedString(titleAttr,
Locale.ENGLISH) : null;
- LocalizedString description = descriptionAttr != null ? new
LocalizedString(descriptionAttr, Locale.ENGLISH) : null;
- int width = (widthAttr != null && widthAttr.length() > 0) ?
Integer.parseInt(widthAttr) : 320;
- int height = (heightAttr != null && heightAttr.length() > 0) ?
Integer.parseInt(heightAttr) : 200;
- return new GGWidget(url.toString(), prefsInfo, title, description, width,
height);
- }
- else
- {
- throw new Exception(); // Basic for now
- }
- }
-}
Deleted: trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetProvider.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetProvider.java 2007-03-09
08:05:41 UTC (rev 6615)
+++ trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetProvider.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -1,284 +0,0 @@
-/******************************************************************************
- * JBoss, a division of Red Hat *
- * Copyright 2006, Red Hat Middleware, LLC, and individual *
- * contributors as indicated by the @authors tag. See the *
- * copyright.txt in the distribution for a full listing of *
- * individual contributors. *
- * *
- * This is free software; you can redistribute it and/or modify it *
- * under the terms of the GNU Lesser General Public License as *
- * published by the Free Software Foundation; either version 2.1 of *
- * the License, or (at your option) any later version. *
- * *
- * This software is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
- * Lesser General Public License for more details. *
- * *
- * You should have received a copy of the GNU Lesser General Public *
- * License along with this software; if not, write to the Free *
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
- ******************************************************************************/
-package org.jboss.portal.widget.google;
-
-import java.net.URL;
-import java.net.MalformedURLException;
-import java.io.InputStreamReader;
-import java.io.ByteArrayInputStream;
-import java.util.StringTokenizer;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedHashMap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ArrayList;
-
-import org.jboss.portal.widget.WidgetProvider;
-import org.jboss.portal.widget.Widget;
-import org.jboss.portal.common.util.URLTools;
-import org.jboss.portal.common.concurrent.loader.ObjectBatch;
-import org.jboss.portal.common.concurrent.loader.ObjectLoader;
-import org.jboss.portal.common.concurrent.loader.LoadingPolicy;
-import org.jboss.portal.common.concurrent.loader.LoaderContext;
-import org.apache.log4j.Logger;
-
-import javax.swing.text.html.HTML;
-import javax.swing.text.html.HTMLEditorKit;
-import javax.swing.text.MutableAttributeSet;
-
-import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
-import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
-import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
-import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingDeque;
-import edu.emory.mathcs.backport.java.util.concurrent.ExecutorCompletionService;
-
-/**
- * @todo first :
- * - add content type filtering
- * - finish implementation of preferences
- * - use categorization
- * - add pagination
- * - add configuration
- * - add caching policy
- * - add fetching policy
- * - add markup caching in the portlet
- *
- * @todo later but important :
- * - implement widget retrieval defferring when it would be available later
- *
- * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
- * @version $Revision: 1.1 $
- */
-public class GGWidgetProvider implements WidgetProvider
-{
-
- /** . */
- private static final Logger log = Logger.getLogger(GGWidgetProvider.class);
-
- /** . */
- private ObjectBatch batch;
-
- /** . */
- private ExecutorService executor;
-
- /** . */
- private LoaderContext loaderContext;
-
- public GGWidgetProvider()
- {
- }
-
- public void start()
- {
- executor = new ThreadPoolExecutor(4, 4, 0, TimeUnit.SECONDS, new
LinkedBlockingDeque());
- loaderContext = new LoaderContext(new ExecutorCompletionService(executor));
- batch = new ObjectBatch(new ObjectLoader[]{new WidgetBuilder()},
LoadingPolicy.LOAD_ONE);
- }
-
- public void stop()
- {
- executor.shutdownNow();
- executor = null;
- loaderContext = null;
- batch = null;
- }
-
- private Map getMap()
- {
- try
- {
- return (Map)batch.getObject(loaderContext, 0);
- }
- catch (InterruptedException e)
- {
- return null;
- }
- }
-
- public Collection getKeys()
- {
- Map map = getMap();
- if (map == null)
- {
- return Collections.EMPTY_SET;
- }
- return map.keySet();
- }
-
- public Widget getWidget(String key)
- {
- if (key == null)
- {
- throw new IllegalArgumentException();
- }
-
- //
- Map map = getMap();
- if (map == null)
- {
- return null;
- }
-
- //
- GGWidgetBatch batch = (GGWidgetBatch)map.get(key);
- if (batch != null)
- {
- for (int i = 0;i < batch.getSize();i++)
- {
- GGWidget widget = batch.getWidget(loaderContext, i);
- if (widget != null && widget.getId().equals(key))
- {
- return widget;
- }
- }
- }
-
- //
- return null;
- }
-
- private class WidgetBuilder implements ObjectLoader
- {
-
- public Object load()
- {
- try
- {
- // Find widget URLs
- URL url = new
URL("http://www.google.com/ig/directory?synd=open");
-
- // Read fully the URL content first
- log.info("Retrieving " + url);
- byte[] bytes = URLTools.performGET(url, 5000, 5000);
- if (bytes == null)
- {
- throw new Exception("Cannot retrieve " + url);
- }
- log.info("Document " + url + " has been retrieved");
-
- //
- final LinkedHashSet urls = new LinkedHashSet();
- HTMLEditorKit.ParserCallback callback = new HTMLEditorKit.ParserCallback()
- {
- public void handleStartTag(HTML.Tag t, MutableAttributeSet attrSet, int
pos)
- {
- if (t == HTML.Tag.A)
- {
- try
- {
- String href = (String)attrSet.getAttribute(HTML.Attribute.HREF);
- URL url = new URL(href);
- String query = url.getQuery();
- if (query != null)
- {
- Map params = new HashMap();
- StringTokenizer st = new StringTokenizer(query,
"&");
- while (st.hasMoreTokens())
- {
- String pair = st.nextToken();
- int separator = pair.indexOf('=');
- if (separator != -1)
- {
- String left = pair.substring(0, separator);
- String right = pair.substring(separator + 1);
- params.put(left, right);
- }
- }
-
- //
- if (params.containsKey("url"))
- {
- String tmp = (String)params.get("url");
- if (tmp.endsWith(".xml"))
- {
- url = new URL(tmp);
- urls.add(url);
- }
- }
- }
- }
- catch (MalformedURLException ignore)
- {
- }
- }
- }
- };
- HTMLEditorKit.Parser parser = new ParserAccessor().getParser();
- parser.parse(new InputStreamReader(new ByteArrayInputStream(bytes),
"UTF-8"), callback, true);
-
- //
- Map map = new LinkedHashMap();
-
- // Now parse each
- Collection tmp = new ArrayList(BATCH_SIZE);
- for (Iterator i = urls.iterator();i.hasNext();)
- {
- URL widgetURL = (URL)i.next();
- GGWidgetFactory widgetFactory = new GGWidgetFactory(widgetURL);
-
- //
- if (tmp.size() < BATCH_SIZE)
- {
- tmp.add(widgetFactory);
- }
- else
- {
- GGWidgetFactory[] factories = (GGWidgetFactory[])tmp.toArray(new
GGWidgetFactory[tmp.size()]);
- GGWidgetBatch retrievals = new GGWidgetBatch(factories);
- for (int j = 0;j < factories.length;j++)
- {
- String furl = factories[j].getURL().toString();
- map.put(furl, retrievals);
- log.info("Added widget for later retrieval" + furl);
- }
-
- //
- tmp.clear();
- tmp.add(widgetFactory);
- }
- }
-
- //
- return Collections.unmodifiableMap(map);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- return null;
- }
- }
- }
-
- private static final int BATCH_SIZE = 6;
-
- private static class ParserAccessor extends HTMLEditorKit
- {
- public Parser getParser()
- {
- return super.getParser();
- }
- }
-}
Added: trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGProvider.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGProvider.java
(rev 0)
+++
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGProvider.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -0,0 +1,214 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.portal.widget.google.provider;
+
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
+import edu.emory.mathcs.backport.java.util.concurrent.Callable;
+import edu.emory.mathcs.backport.java.util.concurrent.FutureTask;
+import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
+import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
+import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
+import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingDeque;
+
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.util.Collections;
+
+import org.jboss.portal.widget.google.GGWidget;
+import org.jboss.portal.widget.google.provider.GGWidgetBuilder;
+
+/**
+ * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
+ * @version $Revision: 1.1 $
+ */
+public class GGProvider
+{
+
+ /** . */
+ public static final GGQuery INITIAL_QUERY = new GGQuery(0, null, null);
+
+ /** The different descriptors. */
+ private final ConcurrentMap entries = new ConcurrentHashMap();
+
+ /** The query searches. */
+ private final ConcurrentMap searches = new ConcurrentHashMap();
+
+ /** . */
+ private Context context = new Context();
+
+ /** . */
+ private ExecutorService executor;
+
+ public void start()
+ {
+ executor = new ThreadPoolExecutor(4, 4, 0, TimeUnit.SECONDS, new
LinkedBlockingDeque());
+ }
+
+ public void stop()
+ {
+ executor.shutdownNow();
+ executor = null;
+ }
+
+ public GGWidget getWidget(String id)
+ {
+ if (id == null)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ //
+ try
+ {
+ URL url = new URL(id);
+ return context.getWidgetEntry(url).getWidget();
+ }
+ catch (MalformedURLException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public GGQueryResult search(GGQuery query)
+ {
+ if (query == null)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ //
+ QueryEntry tmp = new QueryEntry(query);
+ QueryEntry entry = (QueryEntry)searches.putIfAbsent(query, tmp);
+ if (entry == null)
+ {
+ entry = tmp;
+ entry.retrieve();
+ }
+ return entry.getResult();
+ }
+
+ public class Context
+ {
+ GGProvider.GGWidgetEntry getWidgetEntry(URL url)
+ {
+ GGProvider.GGWidgetEntry tmp = new GGProvider.GGWidgetEntry(url);
+ GGProvider.GGWidgetEntry entry =
(GGProvider.GGWidgetEntry)entries.putIfAbsent(url, tmp);
+ if (entry == null)
+ {
+ entry = tmp;
+ entry.retrieve();
+ }
+ return entry;
+ }
+ }
+
+ public class GGWidgetEntry implements Callable
+ {
+
+ /** The widget id. */
+ private final URL url;
+
+ /** . */
+ private FutureTask future;
+
+ public GGWidgetEntry(URL url)
+ {
+ this.url = url;
+ this.future = new FutureTask(this);
+ }
+
+ public void retrieve()
+ {
+ executor.submit(future);
+ }
+
+ public GGWidget getWidget()
+ {
+ try
+ {
+ return (GGWidget)future.get();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings
| File Templates.
+ return null;
+ }
+ }
+
+ public Object call()
+ {
+ try
+ {
+ GGWidgetBuilder builder = new GGWidgetBuilder(url);
+ return builder.create();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ }
+
+ private class QueryEntry implements Callable
+ {
+
+ /** . */
+ private final GGQuery query;
+
+ /** . */
+ private FutureTask future;
+
+ public QueryEntry(GGQuery query)
+ {
+ this.query = query;
+ this.future = new FutureTask(this);
+ }
+
+ public void retrieve()
+ {
+ executor.submit(future);
+ }
+
+ public GGQueryResult getResult()
+ {
+ try
+ {
+ return (GGQueryResult)future.get();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings
| File Templates.
+ return new GGQueryResult(query, Collections.EMPTY_LIST);
+ }
+ }
+
+ public Object call()
+ {
+ GGQueryResultBuilder builder = new GGQueryResultBuilder(query);
+ return builder.build(context);
+ }
+ }
+}
Added: trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQuery.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQuery.java
(rev 0)
+++ trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQuery.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.portal.widget.google.provider;
+
+/**
+ * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
+ * @version $Revision: 1.1 $
+ */
+public class GGQuery
+{
+
+ /** . */
+ private int start;
+
+ /** Zero or negative means it is not used. */
+ private int num = 24;
+
+ /** . */
+ private String cat;
+
+ /** . */
+ private String q;
+
+ /** . */
+ private int hashCode;
+
+ public GGQuery(int start, String cat, String q)
+ {
+ if (start < 0)
+ {
+ throw new IllegalArgumentException("No negative start");
+ }
+ if (cat != null && cat.length() == 0)
+ {
+ cat = null;
+ }
+ if (q != null && q.length() == 0)
+ {
+ q = null;
+ }
+
+ //
+ this.start = start;
+ this.num = 10;
+ this.cat = cat;
+ this.q = q;
+ this.hashCode = start + (cat == null ? 0 : 1 + cat.hashCode()) + (q == null ? 0 : 1
+ q.hashCode());
+ }
+
+
+ public int getStart()
+ {
+ return start;
+ }
+
+ public int getNum()
+ {
+ return num;
+ }
+
+ public String getCat()
+ {
+ return cat;
+ }
+
+ public String getQ()
+ {
+ return q;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+ if (obj instanceof GGQuery)
+ {
+ GGQuery that = (GGQuery)obj;
+ return
+ (this.start == that.start) &&
+ (this.cat == null ? that.cat == null : this.cat.equals(that.cat)) &&
+ (this.q == null ? that.q == null : this.q.equals(that.q));
+ }
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return hashCode;
+ }
+}
Added: trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResult.java
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResult.java
(rev 0)
+++
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResult.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -0,0 +1,113 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.portal.widget.google.provider;
+
+import org.jboss.portal.widget.google.GGWidget;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
+ * @version $Revision: 1.1 $
+ */
+public class GGQueryResult
+{
+
+ /** . */
+ private final GGQuery query;
+
+ /** . */
+ private List widgetEntries;
+
+ GGQueryResult(GGQuery query, List widgetEntries)
+ {
+ if (query == null)
+ {
+ throw new IllegalArgumentException();
+ }
+ if (widgetEntries == null)
+ {
+ throw new IllegalArgumentException();
+ }
+ this.query = query;
+ this.widgetEntries = widgetEntries;
+ }
+
+ public GGQuery getQuery()
+ {
+ return query;
+ }
+
+ public Iterator getWidgets()
+ {
+ return new WidgetIterator();
+ }
+
+ private class WidgetIterator implements Iterator
+ {
+
+ Iterator iterator = widgetEntries.iterator();
+
+ GGWidget next;
+
+ public boolean hasNext()
+ {
+ if (next == null)
+ {
+ findNext();
+ }
+ return next != null;
+ }
+
+ public Object next()
+ {
+ if (next == null)
+ {
+ findNext();
+ }
+ if (next == null)
+ {
+ throw new NoSuchElementException();
+ }
+ GGWidget tmp = next;
+ next = null;
+ return tmp;
+ }
+
+ void findNext()
+ {
+ while (iterator.hasNext() && next == null)
+ {
+ GGProvider.GGWidgetEntry entry = (GGProvider.GGWidgetEntry)iterator.next();
+ next = entry.getWidget();
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
Added:
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResultBuilder.java
===================================================================
---
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResultBuilder.java
(rev 0)
+++
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGQueryResultBuilder.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -0,0 +1,179 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.portal.widget.google.provider;
+
+import org.jboss.portal.common.util.URLTools;
+
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.HTML;
+import javax.swing.text.MutableAttributeSet;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Collections;
+import java.util.List;
+import java.io.InputStreamReader;
+import java.io.ByteArrayInputStream;
+
+/**
+ * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
+ * @version $Revision: 1.1 $
+ */
+class GGQueryResultBuilder
+{
+
+ /** . */
+ private final GGQuery query;
+
+ public GGQueryResultBuilder(GGQuery query)
+ {
+ if (query == null)
+ {
+ throw new IllegalArgumentException();
+ }
+ this.query = query;
+ }
+
+ private URL getURLQuery() throws MalformedURLException
+ {
+ StringBuffer buffer = new
StringBuffer("http://www.google.com/ig/directory?synd=open");
+ if (query.getStart() > 0)
+ {
+ buffer.append("&start=").append(query.getStart());
+ }
+ if (query.getNum() > 0)
+ {
+ buffer.append("&num=").append(query.getNum());
+ }
+ if (query.getCat() != null)
+ {
+ buffer.append("&cat=").append(query.getCat());
+ }
+ if (query.getQ() != null)
+ {
+ buffer.append("&q=").append(query.getQ());
+ }
+ return new URL(buffer.toString());
+ }
+
+ public GGQueryResult build(GGProvider.Context context)
+ {
+ try
+ {
+ // Find widget URLs
+ URL url = getURLQuery() ;
+
+ // Read fully the URL content first
+ // log.info("Retrieving " + url);
+ byte[] bytes = URLTools.performGET(url, 5000, 5000);
+ if (bytes == null)
+ {
+ throw new Exception("Cannot retrieve " + url);
+ }
+ // log.info("Document " + url + " has been retrieved");
+
+ //
+ final LinkedHashSet urls = new LinkedHashSet();
+ HTMLEditorKit.ParserCallback callback = new HTMLEditorKit.ParserCallback()
+ {
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet attrSet, int pos)
+ {
+ if (t == HTML.Tag.A)
+ {
+ try
+ {
+ String href = (String)attrSet.getAttribute(HTML.Attribute.HREF);
+ URL url = new URL(href);
+ String query = url.getQuery();
+ if (query != null)
+ {
+ Map params = new HashMap();
+ StringTokenizer st = new StringTokenizer(query,
"&");
+ while (st.hasMoreTokens())
+ {
+ String pair = st.nextToken();
+ int separator = pair.indexOf('=');
+ if (separator != -1)
+ {
+ String left = pair.substring(0, separator);
+ String right = pair.substring(separator + 1);
+ params.put(left, right);
+ }
+ }
+
+ //
+ if (params.containsKey("url"))
+ {
+ String tmp = (String)params.get("url");
+ if (tmp.endsWith(".xml"))
+ {
+ url = new URL(tmp);
+ urls.add(url);
+ }
+ }
+ }
+ }
+ catch (MalformedURLException ignore)
+ {
+ }
+ }
+ }
+ };
+ HTMLEditorKit.Parser parser = new ParserAccessor().getParser();
+ parser.parse(new InputStreamReader(new ByteArrayInputStream(bytes),
"UTF-8"), callback, true);
+
+ // Now parse each
+ List widgetEntries = new ArrayList(urls.size());
+ for (Iterator i = urls.iterator();i.hasNext();)
+ {
+ URL widgetURL = (URL)i.next();
+ GGProvider.GGWidgetEntry entry = context.getWidgetEntry(widgetURL);
+ widgetEntries.add(entry);
+ }
+
+ //
+ return new GGQueryResult(query, widgetEntries);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ return new GGQueryResult(query, Collections.EMPTY_LIST);
+ }
+
+ private static class ParserAccessor extends HTMLEditorKit
+ {
+ public Parser getParser()
+ {
+ return super.getParser();
+ }
+ }
+
+}
Copied: trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGWidgetBuilder.java
(from rev 6605,
trunk/widget/src/main/org/jboss/portal/widget/google/GGWidgetFactory.java)
===================================================================
--- trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGWidgetBuilder.java
(rev 0)
+++
trunk/widget/src/main/org/jboss/portal/widget/google/provider/GGWidgetBuilder.java 2007-03-09
19:48:05 UTC (rev 6616)
@@ -0,0 +1,203 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2006, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.portal.widget.google.provider;
+
+import org.jboss.portal.common.util.XML;
+import org.jboss.portal.common.util.LocalizedString;
+import org.jboss.portal.common.util.URLTools;
+import org.jboss.portal.common.concurrent.loader.ObjectLoader;
+import org.jboss.portal.widget.google.type.DataType;
+import org.jboss.portal.widget.google.type.StringType;
+import org.jboss.portal.widget.google.type.LocationType;
+import org.jboss.portal.widget.google.type.HiddenType;
+import org.jboss.portal.widget.google.type.BoolType;
+import org.jboss.portal.widget.google.type.ListType;
+import org.jboss.portal.widget.google.type.EnumType;
+import org.jboss.portal.widget.google.GGWidget;
+import org.jboss.portal.widget.google.GGPreferenceInfo;
+import org.jboss.portal.widget.google.GGPreferencesInfo;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.io.ByteArrayInputStream;
+
+/**
+ * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
+ * @version $Revision: 1.1 $
+ */
+public class GGWidgetBuilder implements ObjectLoader
+{
+
+ /** . */
+ private final URL url;
+
+ public GGWidgetBuilder(URL url)
+ {
+ if (url == null)
+ {
+ throw new IllegalArgumentException("No null URL");
+ }
+ this.url = url;
+ }
+
+ public URL getURL()
+ {
+ return url;
+ }
+
+
+ public Object load()
+ {
+ try
+ {
+ return create();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings |
File Templates.
+
+ //
+ return null;
+ }
+ }
+
+ public GGWidget create() throws Exception
+ {
+ DocumentBuilderFactory factory = XML.getDocumentBuilderFactory();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ byte[] bytes = URLTools.performGET(url, 5000, 5000);
+ if (bytes == null)
+ {
+ throw new Exception("Cannot retrieve document " + url);
+ }
+ Document doc = builder.parse(new ByteArrayInputStream(bytes));
+ Element moduleElt = doc.getDocumentElement();
+
+ //
+ Collection tmp = null;
+ Iterator userPrefsEltIterator = XML.getChildrenIterator(moduleElt,
"UserPref");
+ while (userPrefsEltIterator.hasNext())
+ {
+ Element userPref = (Element)userPrefsEltIterator.next();
+ String nameAttr = userPref.getAttribute("name");
+ String displayNameAttr = userPref.getAttribute("displayName");
+ String urlParamAttr = userPref.getAttribute("urlparam");
+ String dataTypeAttr = userPref.getAttribute("datatype");
+ String requiredAttr = userPref.getAttribute("required");
+ String defaultValueAttr = userPref.getAttribute("default_value");
+
+ // We don't support that for now
+ if (urlParamAttr.length() > 0)
+ {
+ throw new Exception();
+ }
+
+ // String is default type when not specified
+ DataType dataType = StringType.getInstance();
+ if (dataTypeAttr.length() > 0)
+ {
+ int dataTypeOrdinal = DataType.parseDataTypeLiteral(dataTypeAttr);
+ switch(dataTypeOrdinal)
+ {
+ case DataType.HIDDEN:
+ dataType = HiddenType.getInstance();
+ break;
+ case DataType.BOOL:
+ dataType = BoolType.getInstance();
+ break;
+ case DataType.STRING:
+ dataType = StringType.getInstance();
+ break;
+ case DataType.LIST:
+ dataType = ListType.getInstance();
+ break;
+ case DataType.ENUM:
+ Collection values = new ArrayList();
+ for (Iterator i = XML.getChildrenIterator(userPref,
"EnumValue");i.hasNext();)
+ {
+ Element enumValueElt = (Element)i.next();
+ String valueAttr = enumValueElt.getAttribute("value");
+ String displayValueAttr =
enumValueElt.getAttribute("display_value");
+ EnumType.Value value = new EnumType.Value(valueAttr,
displayValueAttr.length() > 0 ? displayValueAttr : null);
+ values.add(value);
+ }
+ dataType = new EnumType(values);
+ break;
+ case DataType.LOCATION:
+ dataType = LocationType.getInstance();
+ break;
+ }
+ }
+
+ //
+ GGPreferenceInfo prefInfo = new GGPreferenceInfo(
+ nameAttr,
+ dataType,
+ displayNameAttr.length() > 0 ? displayNameAttr : null,
+ requiredAttr.length() > 0 ? Boolean.valueOf(requiredAttr).booleanValue() :
false,
+ defaultValueAttr.length() > 0 ? defaultValueAttr : null
+ );
+
+ //
+ if (tmp == null)
+ {
+ tmp = new ArrayList();
+ }
+ tmp.add(prefInfo);
+ }
+ GGPreferencesInfo prefsInfo = GGPreferencesInfo.EMPTY_PREFS;
+ if (tmp != null)
+ {
+ prefsInfo = new GGPreferencesInfo(tmp);
+ }
+
+ //
+ Iterator modulePrefsEltIterator = XML.getChildrenIterator(moduleElt,
"ModulePrefs");
+ if (modulePrefsEltIterator.hasNext())
+ {
+ Element modulePrefsElt = (Element)modulePrefsEltIterator.next();
+ String titleAttr = modulePrefsElt.getAttribute("title");
+ String descriptionAttr = modulePrefsElt.getAttribute("description");
+ String widthAttr = modulePrefsElt.getAttribute("width");
+ String heightAttr = modulePrefsElt.getAttribute("height");
+
+ //
+ LocalizedString title = titleAttr != null ? new LocalizedString(titleAttr,
Locale.ENGLISH) : null;
+ LocalizedString description = descriptionAttr != null ? new
LocalizedString(descriptionAttr, Locale.ENGLISH) : null;
+ int width = (widthAttr != null && widthAttr.length() > 0) ?
Integer.parseInt(widthAttr) : 320;
+ int height = (heightAttr != null && heightAttr.length() > 0) ?
Integer.parseInt(heightAttr) : 200;
+ return new GGWidget(url.toString(), prefsInfo, title, description, width,
height);
+ }
+ else
+ {
+ throw new Exception(); // Basic for now
+ }
+ }
+}