Author: scottbw
Date: Tue May  3 08:42:09 2011
New Revision: 1098967

URL: http://svn.apache.org/viewvc?rev=1098967&view=rev
Log:
Added a controller and helper classes for Widget Updates (see WOOKIE-103). This 
provides an admin-only REST-like API for managing updates; you can get a list 
of available updates, trigger individual updates, or trigger all updates. This 
could be used to create an admin user interface.

Added:
    
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/UpdatesControllerTest.java
    incubator/wookie/trunk/src/org/apache/wookie/updates/
    incubator/wookie/trunk/src/org/apache/wookie/updates/UpdateInformation.java
    incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesController.java
    incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesHelper.java
Modified:
    incubator/wookie/trunk/WebContent/WEB-INF/web.xml

Modified: incubator/wookie/trunk/WebContent/WEB-INF/web.xml
URL: 
http://svn.apache.org/viewvc/incubator/wookie/trunk/WebContent/WEB-INF/web.xml?rev=1098967&r1=1098966&r2=1098967&view=diff
==============================================================================
--- incubator/wookie/trunk/WebContent/WEB-INF/web.xml (original)
+++ incubator/wookie/trunk/WebContent/WEB-INF/web.xml Tue May  3 08:42:09 2011
@@ -121,6 +121,20 @@
                <url-pattern>/participants</url-pattern>
        </servlet-mapping>
        
+       <servlet>
+               <description></description>
+               <display-name>Updates</display-name>
+               <servlet-name>UpdatesServlet</servlet-name>
+               <servlet-class>
+                       org.apache.wookie.updates.UpdatesController
+               </servlet-class>
+               <load-on-startup>2</load-on-startup>
+       </servlet>      
+       <servlet-mapping>
+               <servlet-name>UpdatesServlet</servlet-name>
+               <url-pattern>/updates/*</url-pattern>
+       </servlet-mapping>
+       
        
        <servlet>
                <description></description>
@@ -350,6 +364,19 @@
                                <role-name>widgetadmin</role-name>
                        </auth-constraint>
                </security-constraint>
+                               <security-constraint>           
+                       <web-resource-collection>
+                               
<web-resource-name>UpdatesController</web-resource-name>
+                               <url-pattern>/updates/*</url-pattern>
+                               <http-method>GET</http-method>
+                               <http-method>DELETE</http-method>
+                               <http-method>PUT</http-method>
+                               <http-method>POST</http-method>
+                       </web-resource-collection>              
+                       <auth-constraint>
+                               <role-name>widgetadmin</role-name>
+                       </auth-constraint>
+               </security-constraint>
                <security-constraint>           
                        <web-resource-collection>
                                
<web-resource-name>WidgetServlet</web-resource-name>

Added: 
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/UpdatesControllerTest.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/UpdatesControllerTest.java?rev=1098967&view=auto
==============================================================================
--- 
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/UpdatesControllerTest.java
 (added)
+++ 
incubator/wookie/trunk/src-tests/org/apache/wookie/tests/functional/UpdatesControllerTest.java
 Tue May  3 08:42:09 2011
@@ -0,0 +1,89 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.tests.functional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.wookie.tests.helpers.WidgetUploader;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test cases for Widget Updates controller
+ */
+public class UpdatesControllerTest extends AbstractControllerTest{
+       
+       protected static final String TEST_UPDATES_URL_VALID = 
TEST_SERVER_LOCATION+"updates";
+       
+       @BeforeClass
+       public static void setup(){
+               
+               // Install all the test widgets
+               try {
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-acquisition11/001/ta-ac-001.wgt";);//ac11
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-acquisition13/001/ta-ac-001.wgt";);//ac13
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/003/ta-pr-003.wgt";);//pr203
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/008/ta-pr-008.wgt";);//pr208
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/009/ta-pr-009.wgt";);//pr209
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/010/ta-pr-010.wgt";);//pr210
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/011/ta-pr-011.wgt";);//pr211
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/012/ta-pr-012.wgt";);//pr212
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/013/ta-pr-013.wgt";);//pr213
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/015/ta-pr-015.wgt";);//pr215
+                       
WidgetUploader.uploadWidget("http://dev.w3.org/2006/waf/widgets-updates/test-suite/test-cases/ta-processing2/016/ta-pr-016.wgt";);//pr216
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       @Test
+       public void getUpdatesUnauthorized(){
+               try {
+               HttpClient client = new HttpClient();
+               GetMethod get = new GetMethod(TEST_UPDATES_URL_VALID);
+               client.executeMethod(get);
+               int code = get.getStatusCode();
+               assertEquals(401, code);
+           }
+           catch (Exception e) {
+               e.printStackTrace();
+               fail("get failed");
+           }
+       }
+       
+       @Test
+       public void getUpdates(){
+               try {
+               HttpClient client = new HttpClient();
+               GetMethod get = new GetMethod(TEST_UPDATES_URL_VALID);
+                       setAuthenticationCredentials(client);
+               get.setRequestHeader("Content-type", "text/xml");
+               client.executeMethod(get);
+               int code = get.getStatusCode();
+               assertEquals(200, code);
+           }
+           catch (Exception e) {
+               e.printStackTrace();
+               fail("get failed");
+           }
+       }
+       
+       // NOTE: Actually triggering the updates is tested using the 
conformance tests.
+
+}

Added: 
incubator/wookie/trunk/src/org/apache/wookie/updates/UpdateInformation.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/updates/UpdateInformation.java?rev=1098967&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/updates/UpdateInformation.java 
(added)
+++ incubator/wookie/trunk/src/org/apache/wookie/updates/UpdateInformation.java 
Tue May  3 08:42:09 2011
@@ -0,0 +1,65 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.updates;
+
+import org.apache.wookie.beans.IWidget;
+import org.apache.wookie.helpers.WidgetHelper;
+import org.apache.wookie.w3c.updates.UpdateDescriptionDocument;
+import org.jdom.Element;
+
+/**
+ * Simple class for passing update information, linking an IWidget reference 
to an UpdateDescriptionDocument
+ */
+public class UpdateInformation {
+
+       private IWidget widget;
+       
+       private UpdateDescriptionDocument udd;
+
+       /**
+        * @return the widget
+        */
+       public IWidget getWidget() {
+               return widget;
+       }
+
+       /**
+        * @param widget the widget to set
+        */
+       public void setWidget(IWidget widget) {
+               this.widget = widget;
+       }
+
+       /**
+        * @return the document
+        */
+       public UpdateDescriptionDocument getUpdateDescriptionDocument() {
+               return udd;
+       }
+
+       /**
+        * @param document the document to set
+        */
+       public void setUpdateDescriptionDocument(UpdateDescriptionDocument udd) 
{
+               this.udd = udd;
+       }
+       
+       public Element toXml(){
+               Element element = this.udd.toXml();
+               element.setAttribute("widget", this.widget.getId().toString());
+               element.setAttribute("widget_title", 
WidgetHelper.getEncodedWidgetTitle(this.widget, null));
+               return element;
+       }
+       
+}

Added: 
incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesController.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesController.java?rev=1098967&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesController.java 
(added)
+++ incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesController.java 
Tue May  3 08:42:09 2011
@@ -0,0 +1,210 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.updates;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.log4j.Logger;
+import org.apache.wookie.beans.IServerFeature;
+import org.apache.wookie.beans.IWidget;
+import org.apache.wookie.beans.util.IPersistenceManager;
+import org.apache.wookie.beans.util.PersistenceManagerFactory;
+import org.apache.wookie.controller.Controller;
+import org.apache.wookie.exceptions.InvalidParametersException;
+import org.apache.wookie.exceptions.ResourceDuplicationException;
+import org.apache.wookie.exceptions.ResourceNotFoundException;
+import org.apache.wookie.exceptions.UnauthorizedAccessException;
+import org.apache.wookie.helpers.FlashMessage;
+import org.apache.wookie.helpers.WidgetFactory;
+import org.apache.wookie.util.html.StartPageProcessor;
+import org.apache.wookie.w3c.W3CWidget;
+import org.apache.wookie.w3c.W3CWidgetFactory;
+import org.apache.wookie.w3c.exceptions.BadManifestException;
+import org.apache.wookie.w3c.exceptions.BadWidgetZipFileException;
+import org.apache.wookie.w3c.exceptions.InvalidContentTypeException;
+import org.apache.wookie.w3c.updates.UpdateDescriptionDocument;
+import org.apache.wookie.w3c.updates.UpdateUtils;
+
+/**
+ * Controller for managing widget updates
+ * 
+ * GET - gets the list of updates available
+ * GET/{internal_widget_id} - redirects you to the UDD for the widget
+ * POST - attempts to apply ALL available updates
+ * PUT/{internal_widget_id} - applies update to specified widget only
+ */
+public class UpdatesController extends Controller {
+
+       private static final long serialVersionUID = 5891956245633379750L;
+       
+       static Logger _logger = 
Logger.getLogger(UpdatesController.class.getName());
+
+       @Override
+       protected void index(HttpServletRequest request,
+                       HttpServletResponse response) throws 
UnauthorizedAccessException,
+                       IOException {
+               List<UpdateInformation> updates = getAllUpdates();
+               response.setStatus(HttpServletResponse.SC_OK);
+               returnXml(UpdatesHelper.createXML(updates),response);
+       }
+
+       /* (non-Javadoc)
+        * @see org.apache.wookie.controller.Controller#show(java.lang.String, 
javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+        */
+       @Override
+       protected void show(String resourceId, HttpServletRequest request,
+                       HttpServletResponse response) throws 
ResourceNotFoundException,
+                       UnauthorizedAccessException, IOException {
+               // attempt to get specific widget by id
+               IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
+               IWidget widget = persistenceManager.findById(IWidget.class, 
resourceId);
+               if (widget == null) throw new ResourceNotFoundException();
+               // redirect to the UDD
+               if (widget.getUpdateLocation() ==  null) throw new 
ResourceNotFoundException();
+               response.sendRedirect(widget.getUpdateLocation());
+       }
+
+       @Override
+       protected boolean create(String resourceId, HttpServletRequest request)
+                       throws ResourceDuplicationException, 
InvalidParametersException,
+                       UnauthorizedAccessException {
+               
+                       boolean onlyUseHttps = 
Boolean.parseBoolean(request.getParameter("use-https"));
+                       if (!onlyUseHttps) _logger.warn("checking for updates 
using non-secure method");
+                       IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
+                       IWidget[] widgets = 
persistenceManager.findAll(IWidget.class);
+                       W3CWidgetFactory factory  = 
getFactory(request.getSession().getServletContext());
+                       for (IWidget widget: widgets){
+                               try {
+                                       installUpdate(factory, widget, 
onlyUseHttps);
+                               } catch (Exception e) {
+                                       _logger.warn(e.getMessage(), e);
+                               }
+                       }       
+                       return true;
+       }
+
+       @Override
+       protected void update(String resourceId, HttpServletRequest request)
+                       throws ResourceNotFoundException, 
InvalidParametersException,
+                       UnauthorizedAccessException {
+                       // attempt to get specific widget by id
+                       IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
+                       IWidget widget = 
persistenceManager.findById(IWidget.class, resourceId);
+                       if (widget == null) throw new 
ResourceNotFoundException();
+                       // FIXME localize error messages
+                       try {
+                               W3CWidgetFactory factory  = 
getFactory(request.getSession().getServletContext());
+                               installUpdate(factory, widget, false);
+                       } catch (IOException e) {
+                               _logger.warn("Problem updating "+resourceId+": 
widget couldn't be downloaded");
+                               throw new InvalidParametersException();
+                       } catch (InvalidContentTypeException e) {
+                               _logger.warn("Problem updating "+resourceId+": 
incorrect content type");
+                               throw new InvalidParametersException();
+                       } catch (BadWidgetZipFileException e) {
+                               _logger.warn("Problem updating "+resourceId+": 
update is an invalid widget package");
+                               throw new InvalidParametersException();
+                       } catch (BadManifestException e) {
+                               _logger.warn("Problem updating "+resourceId+": 
update has an invalid config.xml");
+                               throw new InvalidParametersException();
+                       } catch (Exception e) {
+                               _logger.warn("Problem updating "+resourceId+": 
"+e.getMessage());
+                               throw new InvalidParametersException();
+                       }
+       }
+       
+       /**
+        * Installs an update only for the specified widget
+        * @param factory a W3CWidgetFactory configured for this server
+        * @param widget the Widget to update
+        * @param doc the UpdateDescriptionDocument for the Widget update
+        * @param onlyUseHttps true to only install over HTTPS
+        * @throws Exception 
+        * @throws IOException 
+        * @throws BadManifestException 
+        * @throws BadWidgetZipFileException 
+        * @throws InvalidContentTypeException 
+        */
+       // FIXME localize messages
+       private void installUpdate(W3CWidgetFactory factory, IWidget widget, 
boolean onlyUseHttps) throws InvalidContentTypeException, 
BadWidgetZipFileException, BadManifestException, IOException, Exception{
+               W3CWidget updatedWidget = UpdateUtils.getUpdate(factory, 
widget.getGuid(), widget.getUpdateLocation(), widget.getVersion(), 
onlyUseHttps);
+               if (updatedWidget != null){
+                       WidgetFactory.update(updatedWidget, widget, false);
+                       _logger.info("Successfully updated "+widget.getGuid()+" 
to version "+updatedWidget.getVersion());
+                       FlashMessage.getInstance().message("Successfully 
updated "+widget.getGuid()+" to version "+updatedWidget.getVersion());
+               }
+       }
+       
+       /**
+        * Obtain a W3CWidgetFactory configured for this servlet context
+        * @param context
+        * @return the factory
+        * @throws IOException
+        */
+       private W3CWidgetFactory getFactory(ServletContext context){
+               Configuration properties = (Configuration) 
context.getAttribute("properties"); //$NON-NLS-1$
+               W3CWidgetFactory factory = new W3CWidgetFactory();
+               final String[] locales = 
properties.getStringArray("widget.locales");
+               factory.setLocales(locales);
+               
factory.setLocalPath(context.getContextPath()+properties.getString("widget.widgetfolder"));
+               final String WIDGETFOLDER = 
context.getRealPath(properties.getString("widget.widgetfolder"));//$NON-NLS-1$
+               try {
+                       factory.setOutputDirectory(WIDGETFOLDER);
+               } catch (IOException e) {
+                       _logger.error(e);
+               }
+               // Configure the widget factory with the installed feature set
+               IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
+               IServerFeature[] features = 
persistenceManager.findAll(IServerFeature.class);
+               String[] featureNames = new String[features.length];
+               for (int i=0;i<features.length;i++){
+                       featureNames[i] = features[i].getFeatureName();
+               }
+               factory.setFeatures(featureNames);
+               factory.setStartPageProcessor(new StartPageProcessor());
+               return factory;
+       }
+       
+       /**
+        * Get available updates for all installed widgets. Note that this 
method takes a long
+        * time to return as it has to poll all the available update sites, so 
where possible
+        * cache the returned updates
+        * @return a list containing all the updates available.
+        */
+       public List<UpdateInformation> getAllUpdates(){
+               ArrayList<UpdateInformation> updates = new 
ArrayList<UpdateInformation>();
+               IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
+               IWidget[] widgets = persistenceManager.findAll(IWidget.class);
+               for (IWidget widget: widgets){
+                       UpdateDescriptionDocument udd = 
UpdateUtils.checkForUpdate(widget.getUpdateLocation(), widget.getVersion());
+                       if (udd != null){
+                               UpdateInformation info = new 
UpdateInformation();
+                               info.setUpdateDescriptionDocument(udd);
+                               info.setWidget(widget);
+                               updates.add(info);
+                       }
+               }       
+               return updates;
+       }
+       
+
+}

Added: incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesHelper.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesHelper.java?rev=1098967&view=auto
==============================================================================
--- incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesHelper.java 
(added)
+++ incubator/wookie/trunk/src/org/apache/wookie/updates/UpdatesHelper.java Tue 
May  3 08:42:09 2011
@@ -0,0 +1,40 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wookie.updates;
+
+import java.util.List;
+
+import org.apache.wookie.w3c.IW3CXMLConfiguration;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.output.XMLOutputter;
+
+/**
+ * View Helper for updates
+ */
+public class UpdatesHelper {
+
+       public static String createXML(
+                       List<UpdateInformation> updates) {
+               Document document = new Document();
+               Element root = new 
Element("updates",IW3CXMLConfiguration.MANIFEST_NAMESPACE);
+               for (UpdateInformation info: updates){
+                       root.addContent(info.toXml());
+               }
+               document.setRootElement(root);
+               XMLOutputter outputter = new XMLOutputter();
+               return outputter.outputString(document);
+       }
+
+}


Reply via email to