Author: marrs
Date: Fri Aug 16 14:16:56 2013
New Revision: 1514721
URL: http://svn.apache.org/r1514721
Log:
ACE-342 Added initial server side code to fetch versions and bundles.
Added:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
ace/trunk/run-server-allinone/conf/org.apache.ace.deployment.servlet.agent.cfg
Modified:
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/DeploymentIntegrationTest.java
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
ace/trunk/org.apache.ace.repository.itest/bnd.bnd
ace/trunk/run-server-allinone/server-allinone.bndrun
Modified:
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/DeploymentIntegrationTest.java
URL:
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/DeploymentIntegrationTest.java?rev=1514721&r1=1514720&r2=1514721&view=diff
==============================================================================
---
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/DeploymentIntegrationTest.java
(original)
+++
ace/trunk/org.apache.ace.deployment.itest/src/org/apache/ace/it/deployment/DeploymentIntegrationTest.java
Fri Aug 16 14:16:56 2013
@@ -360,7 +360,7 @@ public class DeploymentIntegrationTest e
private void configureServer() throws IOException {
// configure data bundle
- configure(org.apache.ace.deployment.servlet.Activator.PID,
HttpConstants.ENDPOINT, "/deployment", "authentication.enabled", "false");
+ configure(org.apache.ace.deployment.servlet.Activator.DEPLOYMENT_PID,
HttpConstants.ENDPOINT, "/deployment", "authentication.enabled", "false");
// configure file based backend
configure(org.apache.ace.deployment.provider.filebased.Activator.PID,
"BaseDirectoryName", m_tempDir.getAbsolutePath());
}
Modified:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
URL:
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java?rev=1514721&r1=1514720&r2=1514721&view=diff
==============================================================================
---
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
(original)
+++
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/Activator.java
Fri Aug 16 14:16:56 2013
@@ -20,6 +20,7 @@ package org.apache.ace.deployment.servle
import javax.servlet.Servlet;
+import org.apache.ace.connectionfactory.ConnectionFactory;
import org.apache.ace.deployment.processor.DeploymentProcessor;
import org.apache.ace.deployment.provider.DeploymentProvider;
import org.apache.ace.deployment.streamgenerator.StreamGenerator;
@@ -29,19 +30,27 @@ import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
public class Activator extends DependencyActivatorBase {
- public static final String PID = "org.apache.ace.deployment.servlet";
+ public static final String DEPLOYMENT_PID =
"org.apache.ace.deployment.servlet";
+ public static final String AGENT_PID =
"org.apache.ace.deployment.servlet.agent";
@Override
public void init(BundleContext context, DependencyManager manager) throws
Exception {
manager.add(createComponent()
.setInterface(Servlet.class.getName(), null)
.setImplementation(DeploymentServlet.class)
-
.add(createConfigurationDependency().setPropagate(true).setPid(PID))
+
.add(createConfigurationDependency().setPropagate(true).setPid(DEPLOYMENT_PID))
.add(createServiceDependency().setService(StreamGenerator.class).setRequired(true))
.add(createServiceDependency().setService(DeploymentProvider.class).setRequired(true))
.add(createServiceDependency().setService(DeploymentProcessor.class).setRequired(false).setCallbacks("addProcessor",
"removeProcessor"))
.add(createServiceDependency().setService(LogService.class).setRequired(false))
);
+ manager.add(createComponent()
+ .setInterface(Servlet.class.getName(), null)
+ .setImplementation(AgentDeploymentServlet.class)
+
.add(createConfigurationDependency().setPropagate(true).setPid(AGENT_PID))
+
.add(createServiceDependency().setService(ConnectionFactory.class).setRequired(true))
+
.add(createServiceDependency().setService(LogService.class).setRequired(false))
+ );
}
@Override
Added:
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
URL:
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java?rev=1514721&view=auto
==============================================================================
---
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
(added)
+++
ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/AgentDeploymentServlet.java
Fri Aug 16 14:16:56 2013
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.ace.deployment.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.ace.authentication.api.AuthenticationService;
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.Version;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+public class AgentDeploymentServlet extends HttpServlet implements
ManagedService {
+ private static final int BUFFER_SIZE = 1024 * 32;
+ /** A boolean denoting whether or not authentication is enabled. */
+ private static final String KEY_USE_AUTHENTICATION =
"authentication.enabled";
+ /** URL to the OBR that is used for finding versions of the agent. */
+ private static final String KEY_OBR_URL = "obr.url";
+
+ public static final String VERSIONS = "versions";
+ public static final String BUNDLE_MIMETYPE = "application/octet-stream";
+ public static final String TEXT_MIMETYPE = "text/plain";
+
+ // injected by Dependency Manager
+ private volatile DependencyManager m_dm;
+ private volatile LogService m_log;
+ private volatile AuthenticationService m_authService;
+ private volatile ConnectionFactory m_connectionFactory;
+
+ private volatile boolean m_useAuth = false;
+ private static final String XPATH_QUERY = "/repository/resource[@uri]";
+ private final String m_repositoryXML = "repository.xml";
+ private URL m_obrURL;
+
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
+ try {
+ String[] pathElements =
verifyAndGetPathElements(request.getPathInfo());
+ String targetID = pathElements[1]; // in the future we might use
this for per target approval
+ String agentID = pathElements[2];
+ int numberOfElements = pathElements.length;
+ if (numberOfElements == 4) {
+ handleVersionsRequest(getVersions(agentID), response);
+ }
+ else {
+ handlePackageDelivery(agentID, new Version(pathElements[4]),
request, response);
+ }
+ }
+ catch (AceRestException e) {
+ m_log.log(LogService.LOG_WARNING, e.getMessage(), e);
+ e.handleAsHttpError(response);
+ }
+ }
+
+ private String[] verifyAndGetPathElements(String path) throws
AceRestException {
+ if (path == null) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI is invalid, no path specified.");
+ }
+ String[] elements = path.split("/");
+ int numberOfElements = elements.length;
+ if ((numberOfElements < 4) || (numberOfElements > 5) ||
!VERSIONS.equals(elements[3])) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI elements are invalid: " + path);
+ }
+ return elements;
+ }
+
+ private List<Version> getVersions(String agentID) throws AceRestException {
+ try {
+ return getVersionsFromOBR(m_obrURL, agentID);
+ }
+ catch (XPathExpressionException e) {
+ throw new AceRestException(HttpServletResponse.SC_NOT_FOUND,
"Unknown agent (" + agentID + ")");
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Error getting available
versions.", ioe);
+ throw new
AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error getting
available versions.");
+ }
+ }
+
+ private List<Version> getVersionsFromOBR(URL obrBaseUrl, String agentID)
throws XPathExpressionException, IOException {
+ InputStream input = null;
+ NodeList resources = getOBRNodeList(input);
+ List<Version> obrList = new ArrayList<Version>();
+ for (int nResource = 0; nResource < resources.getLength();
nResource++) {
+ Node resource = resources.item(nResource);
+ NamedNodeMap attr = resource.getAttributes();
+
+ String uri = getNamedItemText(attr, "uri");
+ if (uri == null || uri.equals("")) {
+ m_log.log(LogService.LOG_ERROR, "Skipping resource without uri
from repository " + obrBaseUrl);
+ continue;
+ }
+
+ String symbolicname = getNamedItemText(attr, "symbolicname");
+ if (agentID.equals(symbolicname)) {
+ Version version = new Version(getNamedItemText(attr,
"version"));
+ obrList.add(version);
+ }
+ }
+ Collections.sort(obrList);
+ return obrList;
+ }
+ private InputStream getAgentFromOBR(URL obrBaseUrl, String agentID,
Version version) throws XPathExpressionException, IOException {
+ InputStream input = null;
+ NodeList resources = getOBRNodeList(input);
+ for (int nResource = 0; nResource < resources.getLength();
nResource++) {
+ Node resource = resources.item(nResource);
+ NamedNodeMap attr = resource.getAttributes();
+
+ String uri = getNamedItemText(attr, "uri");
+ if (uri == null || uri.equals("")) {
+ m_log.log(LogService.LOG_ERROR, "Skipping resource without uri
from repository " + obrBaseUrl);
+ continue;
+ }
+
+ String symbolicname = getNamedItemText(attr, "symbolicname");
+ Version bundleVersion = new Version(getNamedItemText(attr,
"version"));
+ if (agentID.equals(symbolicname) && version.equals(bundleVersion))
{
+ URL url = new URL(obrBaseUrl, getNamedItemText(attr, "uri"));
+ URLConnection connection = openConnection(url);
+ return connection.getInputStream();
+ }
+ }
+ return null;
+ }
+
+ private NodeList getOBRNodeList(InputStream input) throws
XPathExpressionException, IOException {
+ NodeList resources;
+ try {
+ URLConnection connection = openConnection(createOBRURL());
+ // We always want the newest repository.xml file.
+ connection.setUseCaches(false);
+
+ input = connection.getInputStream();
+
+ try {
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ // this XPath expressing will find all 'resource' elements
which
+ // have an attribute 'uri'.
+ resources = (NodeList) xpath.evaluate(XPATH_QUERY, new
InputSource(input), XPathConstants.NODESET);
+ }
+ catch (XPathExpressionException e) {
+ m_log.log(LogService.LOG_ERROR, "Error evaluating XPath
expression.", e);
+ throw e;
+ }
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_ERROR, "Error reading repository
metadata.", e);
+ throw e;
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ // too bad, no worries.
+ }
+ }
+ }
+ return resources;
+ }
+
+ private URL createOBRURL() throws MalformedURLException {
+ try {
+ return new URL(m_obrURL, m_repositoryXML);
+ }
+ catch (MalformedURLException e) {
+ m_log.log(LogService.LOG_ERROR, "Error retrieving repository.xml
from " + m_obrURL);
+ throw e;
+ }
+ }
+ protected URLConnection openConnection(URL url) throws IOException {
+ return m_connectionFactory.createConnection(url);
+ }
+ /**
+ * Gets the actual text from a named item contained in the given node map.
+ *
+ * @param map the node map to get the named item from;
+ * @param name the name of the item to get.
+ * @return the text of the named item, can be <code>null</code> in case
the named item does not exist, or has no text.
+ */
+ private static String getNamedItemText(NamedNodeMap map, String name) {
+ Node namedItem = map.getNamedItem(name);
+ if (namedItem == null) {
+ return null;
+ }
+ else {
+ return namedItem.getTextContent();
+ }
+ }
+
+ private void handleVersionsRequest(List<Version> versions,
HttpServletResponse response) throws AceRestException {
+ ServletOutputStream output = null;
+
+ response.setContentType(TEXT_MIMETYPE);
+ try {
+ output = response.getOutputStream();
+ for (Version version : versions) {
+ output.print(version.toString());
+ output.print("\n");
+ }
+ }
+ catch (IOException e) {
+ throw new AceRestException(HttpServletResponse.SC_BAD_REQUEST,
"Request URI is invalid");
+ }
+ finally {
+ tryClose(output);
+ }
+ }
+
+ private void handlePackageDelivery(final String agentID, final Version
version, final HttpServletRequest request, final HttpServletResponse response)
throws AceRestException {
+ ServletOutputStream output = null;
+
+ try {
+ InputStream inputStream = null;
+ try {
+ inputStream = getAgentFromOBR(m_obrURL, agentID, version);
+ if (inputStream == null) {
+ throw (AceRestException) new
AceRestException(HttpServletResponse.SC_NOT_FOUND, "Agent not found in OBR.");
+ }
+ }
+ catch (XPathExpressionException e) {
+ throw (AceRestException) new
AceRestException(HttpServletResponse.SC_NOT_FOUND, "Agent not found: error
parsing OBR").initCause(e);
+ }
+ finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ response.setContentType(BUNDLE_MIMETYPE);
+ output = response.getOutputStream();
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int bytes;
+ while ((bytes = inputStream.read(buffer)) != -1) {
+ output.write(buffer, 0, bytes);
+ }
+ }
+ catch (IllegalArgumentException e) {
+ throw (AceRestException) new
AceRestException(HttpServletResponse.SC_BAD_REQUEST, "Request URI is
invalid").initCause(e);
+ }
+ catch (IOException e) {
+ throw (AceRestException) new
AceRestException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not
deliver package").initCause(e);
+ }
+ finally {
+ tryClose(output);
+ }
+ }
+
+ private void tryClose(OutputStream output) {
+ try {
+ if (output != null) {
+ output.close();
+ }
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_WARNING, "Exception trying to close
stream after request. ", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void updated(Dictionary settings) throws ConfigurationException {
+ if (settings != null) {
+ String useAuthString = (String)
settings.get(KEY_USE_AUTHENTICATION);
+ if (useAuthString == null
+ || !("true".equalsIgnoreCase(useAuthString) ||
"false".equalsIgnoreCase(useAuthString))) {
+ throw new ConfigurationException(KEY_USE_AUTHENTICATION,
"Missing or invalid value!");
+ }
+ boolean useAuth = Boolean.parseBoolean(useAuthString);
+ m_useAuth = useAuth;
+
+ String obrURL = (String) settings.get(KEY_OBR_URL);
+ try {
+ URL url = new URL(obrURL);
+ m_obrURL = url;
+ }
+ catch (MalformedURLException e) {
+ throw new ConfigurationException(KEY_OBR_URL, "Invalid value,
not a URL.", e);
+ }
+ if (obrURL == null) {
+ throw new ConfigurationException(KEY_OBR_URL, "Missing " +
+ "value!");
+ }
+ }
+ else {
+ m_useAuth = false;
+ m_obrURL = null;
+ }
+ }
+}
Modified: ace/trunk/org.apache.ace.repository.itest/bnd.bnd
URL:
http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.repository.itest/bnd.bnd?rev=1514721&r1=1514720&r2=1514721&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.repository.itest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.repository.itest/bnd.bnd Fri Aug 16 14:16:56 2013
@@ -11,8 +11,7 @@ Test-Cases: ${classes;CONCRETE;EXTENDS;o
org.apache.felix.dependencymanager
-runfw: org.apache.felix.framework;version='[4,5)'
-runvm: -ea
--runbundles: \
- osgi.cmpn,\
+-runbundles: osgi.cmpn,\
org.apache.felix.log,\
org.apache.felix.dependencymanager,\
org.apache.felix.configadmin,\
@@ -25,7 +24,11 @@ Test-Cases: ${classes;CONCRETE;EXTENDS;o
org.apache.ace.range.api;version=latest,\
org.apache.ace.repository.api;version=latest,\
org.apache.ace.repository.impl;version=latest,\
- org.apache.ace.repository.servlet;version=latest
+ org.apache.ace.repository.servlet;version=latest,\
+ org.apache.felix.gogo.command,\
+ org.apache.felix.gogo.runtime,\
+ org.apache.felix.gogo.shell,\
+ org.apache.felix.dependencymanager.shell
Private-Package: org.apache.ace.it.repository
Bundle-Version: 1.0.0
Bundle-Name: Apache ACE Repository itest
Added:
ace/trunk/run-server-allinone/conf/org.apache.ace.deployment.servlet.agent.cfg
URL:
http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/conf/org.apache.ace.deployment.servlet.agent.cfg?rev=1514721&view=auto
==============================================================================
---
ace/trunk/run-server-allinone/conf/org.apache.ace.deployment.servlet.agent.cfg
(added)
+++
ace/trunk/run-server-allinone/conf/org.apache.ace.deployment.servlet.agent.cfg
Fri Aug 16 14:16:56 2013
@@ -0,0 +1,4 @@
+org.apache.ace.server.servlet.endpoint=/agent
+# OBR settings
+obr.url = http://localhost:${org.apache.ace.server.port}/obr/
+authentication.enabled = false
Modified: ace/trunk/run-server-allinone/server-allinone.bndrun
URL:
http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/server-allinone.bndrun?rev=1514721&r1=1514720&r2=1514721&view=diff
==============================================================================
--- ace/trunk/run-server-allinone/server-allinone.bndrun (original)
+++ ace/trunk/run-server-allinone/server-allinone.bndrun Fri Aug 16 14:16:56
2013
@@ -73,4 +73,4 @@
org.apache.felix.log.maxSize=1000,\
launch.keep=true,\
launch.storage.dir=bundle-cache
--runvm: -Xmx1G
\ No newline at end of file
+-runvm: -Xmx1G
-agentpath:/Applications/YourKit_Java_Profiler_12.0.5.app/bin/mac/libyjpagent.jnilib
\ No newline at end of file