You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wookie.apache.org by sc...@apache.org on 2011/05/03 10:42:09 UTC

svn commit: r1098967 - in /incubator/wookie/trunk: WebContent/WEB-INF/ src-tests/org/apache/wookie/tests/functional/ src/org/apache/wookie/updates/

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);
+	}
+
+}