You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by sf...@apache.org on 2006/07/20 11:36:50 UTC
svn commit: r423855 [2/5] - in
/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector: ./ src/
src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/felix/ src/main/java/org/apache/felix/mosgi/
src/main...
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptor.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptor.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+import javax.management.JMException;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.AdaptorServerSocketFactory;
+import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.PlainAdaptorServerSocketFactory;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.util.Base64Codec;
+
+import org.apache.felix.mosgi.jmx.httpconnector.HttpConnectorActivator;
+
+/**
+ * HttpAdaptor sets the basic adaptor listening for HTTP requests
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class HttpAdaptor implements HttpAdaptorMBean, MBeanRegistration
+{
+ private static final String VERSION = "2.0 Beta 1";
+
+ /** Port to listen for connections */
+ private int port = 8080;
+
+ /** Host where to set the server socket */
+ private String host = "localhost";
+
+ /** Target server */
+ private MBeanServer server;
+
+ /** Server socket */
+ private ServerSocket serverSocket;
+
+ /** Indicates whether the server is running */
+ private boolean alive;
+
+ /** Map of commands indexed by the request path */
+ private Map commands = new HashMap();
+
+ /** Target processor */
+ private ProcessorMBean processor = null;
+
+ /** Target processor name */
+ private ObjectName processorName = null;
+
+ /** Default processor */
+ private ProcessorMBean defaultProcessor = new DefaultProcessor();
+
+ private String authenticationMethod = "none";
+
+ // Should be dependant on the server?
+ private String realm="MX4J";
+
+ private Map authorizations = new HashMap();
+
+ private AdaptorServerSocketFactory socketFactory = null;
+
+ private ObjectName factoryName;
+
+ private String processorClass;
+
+ private Date startDate;
+
+ private long requestsCount;
+
+ private String[][] defaultCommandProcessors = {
+ {"server", "mx4j.tools.adaptor.http.ServerCommandProcessor"},
+ {"serverbydomain", "mx4j.tools.adaptor.http.ServerByDomainCommandProcessor"},
+ {"mbean", "mx4j.tools.adaptor.http.MBeanCommandProcessor"},
+ {"setattributes", "mx4j.tools.adaptor.http.SetAttributesCommandProcessor"},
+ {"setattribute", "mx4j.tools.adaptor.http.SetAttributeCommandProcessor"},
+ {"getattribute", "mx4j.tools.adaptor.http.GetAttributeCommandProcessor"},
+ {"delete", "mx4j.tools.adaptor.http.DeleteMBeanCommandProcessor"},
+ {"invoke", "mx4j.tools.adaptor.http.InvokeOperationCommandProcessor"},
+ {"create", "mx4j.tools.adaptor.http.CreateMBeanCommandProcessor"},
+ {"constructors", "mx4j.tools.adaptor.http.ConstructorsCommandProcessor"},
+ {"empty", "mx4j.tools.adaptor.http.EmptyCommandProcessor"}};
+
+// {"relation", "mx4j.tools.adaptor.http.RelationCommandProcessor"},
+
+ private DocumentBuilder builder;
+
+ /**
+ * Default Constructor added so that we can have some additional
+ * constructors as well.
+ */
+ public HttpAdaptor()
+ {
+ }
+
+ /**
+ * Overloaded constructor to allow the port to be set.
+ * The reason this was added was to allow the loading of this adaptor by
+ * the dynamic loading service of the MBean server and have the port set
+ * from a param in the mlet file. Example: (replaced lt & gt symbol with [])
+ * <br>[mlet code="mx4j.tools.adaptor.http.HttpAdaptor"
+ * <br> archive="mx4j.jar"
+ * <br> name="Server:name=HttpAdaptor"]
+ * <br> [arg type="int" value="12345"]
+ * <br>[/mlet]
+ *
+ * <p>This constructor uses the default host or the host must be set later.
+ * @param port The port on which the HttpAdaptor should listen
+ */
+ public HttpAdaptor(int port)
+ {
+ this.port = port;
+ }
+
+
+ /**
+ * Overloaded constructor to allow the host to be set.
+ * The reason this was added was to allow the loading of this adaptor by
+ * the dynamic loading service of the MBean server and have the host set
+ * from a param in the mlet file. Example: (replaced lt & gt symbol with [])
+ * <br>[mlet code="mx4j.tools.adaptor.http.HttpAdaptor"
+ * <br> archive="mx4j.jar"
+ * <br> name="Server:name=HttpAdaptor"]
+ * <br> [arg type="java.lang.String" value="someserver.somehost.com"]
+ * <br>[/mlet]
+ *
+ * <p>This constructor uses the default port or the port must be set later.
+ * @param host The host on which the HttpAdaptor should listen
+ */
+ public HttpAdaptor(String host)
+ {
+ this.host = host;
+ }
+
+
+ /**
+ * Overloaded constructor to allow the port to be set.
+ * The reason this was added was to allow the loading of this adaptor by
+ * the dynamic loading service of the MBean server and have the port set
+ * from a param in the mlet file. Example: (replaced lt & gt symbol with [])
+ * NOTE that the port must come before the host in the arg list of the mlet
+ * <br>[mlet code="mx4j.tools.adaptor.http.HttpAdaptor"
+ * <br> archive="mx4j.jar"
+ * <br> name="Server:name=HttpAdaptor"]
+ * <br> [arg type="int" value="12345"]
+ * <br> [arg type="java.lang.String" value="someserver.somehost.com"]
+ * <br>[/mlet]
+ *
+ * @param port The port on which the HttpAdaptor should listen
+ * @param host The host on which the HttpAdaptor should listen
+ */
+ public HttpAdaptor(int port, String host)
+ {
+ this.port = port;
+ this.host = host;
+ }
+
+
+ /**
+ * Sets the value of the server's port
+ *
+ * @param port the new port's value
+ */
+ public void setPort(int port)
+ {
+ if (alive)
+ {
+ throw new IllegalArgumentException("Not possible to change port with the server running");
+ }
+ this.port = port;
+ }
+
+
+ /**
+ * Returns the port where the server is running on. Default is 8080
+ *
+ * @return HTTPServer's port
+ */
+ public int getPort()
+ {
+ return port;
+ }
+
+
+ /**
+ * Sets the host name where the server will be listening
+ *
+ * @param host Server's host
+ */
+ public void setHost(String host)
+ {
+ if (alive)
+ {
+ throw new IllegalArgumentException("Not possible to change port with the server running");
+ }
+ this.host = host;
+ }
+
+
+ /**
+ * Return the host name the server will be listening to. If null the server
+ * listen at the localhost
+ *
+ * @return the current hostname
+ */
+ public String getHost()
+ {
+ return host;
+ }
+
+
+ /**
+ * Sets the Authentication Method.
+ *
+ * @param method none/basic/digest
+ */
+ public void setAuthenticationMethod(String method) {
+ if (alive)
+ {
+ throw new IllegalArgumentException("Not possible to change authentication method with the server running");
+ }
+ if (method == null || !(method.equals("none") || method.equals("basic") || method.equals("digest")))
+ {
+ throw new IllegalArgumentException("Only accept methods none/basic/digest");
+ }
+ this.authenticationMethod = method;
+ }
+
+
+ /**
+ * Authentication Method
+ *
+ * @return authentication method
+ */
+ public String getAuthenticationMethod()
+ {
+ return authenticationMethod;
+ }
+
+
+ /**
+ * Sets the object which will post process the XML results. The last value set
+ * between the setPostProcessor and setPostProcessorName will be the valid one
+ *
+ * @param processor a Post processor object
+ */
+ public void setProcessor(ProcessorMBean processor)
+ {
+ this.processor = processor;
+ this.processorName = null;
+ }
+
+
+ /**
+ * Sets the classname of the object which will post process the XML results. The adaptor
+ * will try to build the object and use the processor name ObjectName to register it
+ * The class name has to implements mx4j.tools.adaptor.http.ProcessorMBean and be MBean
+ * compliant
+ * @param processorClass a Post processor object
+ */
+ public void setProcessorClass(String processorClass)
+ {
+ this.processorClass = processorClass;
+ }
+
+
+ /**
+ * Sets the object name of the PostProcessor MBean. If ProcessorClass is set the processor
+ * will be created
+ * @param processorName a Post processor object
+ */
+ public void setProcessorNameString(String processorName) throws MalformedObjectNameException
+ {
+ this.processorName = new ObjectName(processorName);
+ }
+
+
+ /**
+ * Sets the object name which will post process the XML result. The last value
+ * set between the setPostProcessor and setPostProcessorName will be the valid
+ * one. The MBean will be verified to be of instance HttpPostProcessor
+ * @param processorName The new processorName value
+ */
+ public void setProcessorName(ObjectName processorName)
+ {
+ this.processor = null;
+ this.processorName = processorName;
+ }
+
+ public ProcessorMBean getProcessor()
+ {
+ return this.processor;
+ }
+
+ public ObjectName getProcessorName()
+ {
+ return this.processorName;
+ }
+
+ /**
+ * Sets the object which create the server sockets
+ *
+ * @param factory the socket factory
+ */
+ public void setSocketFactory(AdaptorServerSocketFactory factory)
+ {
+ this.factoryName = null;
+ this.socketFactory = factory;
+ }
+
+
+ /**
+ * Sets the factory's object name which will create the server sockets
+ *
+ * @param factoryName the socket factory
+ */
+ public void setSocketFactoryName(ObjectName factoryName)
+ {
+ this.socketFactory = null;
+ this.factoryName = factoryName;
+ }
+
+
+ /**
+ * Sets the factory's object name which will create the server sockets
+ *
+ * @param factoryName the socket factory
+ */
+ public void setSocketFactoryNameString(String factoryName) throws MalformedObjectNameException
+ {
+ this.socketFactory = null;
+ this.factoryName = new ObjectName(factoryName);
+ }
+
+
+ /**
+ * Indicates whether the server's running
+ *
+ * @return The active value
+ */
+ public boolean isActive()
+ {
+ return alive;
+ }
+
+
+ /**
+ * Starting date
+ *
+ * @return The date when the server was started
+ */
+ public Date getStartDate()
+ {
+ return startDate;
+ }
+
+
+ /**
+ * Requests count
+ *
+ * @return The total of requests served so far
+ */
+ public long getRequestsCount()
+ {
+ return requestsCount;
+ }
+
+
+ /**
+ * Gets the HttpAdaptor version
+ *
+ * @return HttpAdaptor's version
+ */
+ public String getVersion()
+ {
+ return VERSION;
+ }
+
+
+ /**
+ * Adds a command processor object
+ */
+ public void addCommandProcessor(String path, HttpCommandProcessor processor)
+ {
+ commands.put(path, processor);
+ if (alive)
+ {
+ processor.setMBeanServer(server);
+ processor.setDocumentBuilder(builder);
+ }
+ }
+
+
+ /**
+ * Adds a command processor object by class
+ */
+ public void addCommandProcessor(String path, String processorClass)
+ {
+ try
+ {
+ HttpCommandProcessor processor = (HttpCommandProcessor)Class.forName(processorClass).newInstance();
+ addCommandProcessor(path, processor);
+ }
+ catch (Exception e)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,
+ "Exception creating Command Processor of class " + processorClass,
+ e);
+ }
+ }
+
+
+ /**
+ * Removes a command processor object by class
+ */
+ public void removeCommandProcessor(String path)
+ {
+ if (commands.containsKey(path))
+ {
+ commands.remove(path);
+ }
+ }
+
+
+ /**
+ * Starts the server
+ */
+ public void start()
+ throws IOException
+ {
+
+ if (server != null)
+ {
+ serverSocket = createServerSocket();
+
+ if (serverSocket == null)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR, "Server socket is null", null);
+ return;
+ }
+
+ if (processorClass != null && processorName != null)
+ {
+ HttpAdaptor.log(LogService.LOG_INFO,"Building processor class of type " + processorClass + " and name " + processorName, null);
+ try {
+ server.createMBean(processorClass, processorName, null);
+ } catch (JMException e) {
+ HttpAdaptor.log(LogService.LOG_INFO, "Exception creating processor class", e);
+ }
+ }
+
+ Iterator i = commands.values().iterator();
+ while (i.hasNext())
+ {
+ HttpCommandProcessor processor = (HttpCommandProcessor)i.next();
+ processor.setMBeanServer(server);
+ processor.setDocumentBuilder(builder);
+ }
+
+ HttpAdaptor.log(LogService.LOG_INFO, "HttpAdaptor server listening on port " + port, null);
+ alive = true;
+ Thread serverThread = new Thread(
+ new Runnable() {
+ public void run() {
+ HttpAdaptor.log(LogService.LOG_INFO, "HttpAdaptor version " + VERSION + " started",null);
+
+ startDate = new Date();
+ requestsCount = 0;
+
+ while (alive)
+ {
+ try
+ {
+ Socket client = null;
+ client = serverSocket.accept();
+ if (!alive)
+ {
+ break;
+ }
+ requestsCount++;
+ new HttpClient(client).start();
+ }
+ catch (InterruptedIOException e)
+ {
+ continue;
+ }
+ catch (IOException e)
+ {
+ continue;
+ }
+ catch (Exception e)
+ {
+ HttpAdaptor.log(LogService.LOG_WARNING, "Exception during request processing", e);
+ continue;
+ }
+ catch (Error e)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR, "Error during request processing", e);
+ continue;
+ }
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException e) {
+ HttpAdaptor.log(LogService.LOG_WARNING, "Exception closing the server", e);
+ }
+ serverSocket = null;
+ alive = false;
+ HttpAdaptor.log(LogService.LOG_INFO, "Server stopped", null);
+ }
+ });
+ serverThread.start();
+ }
+ else
+ {
+ HttpAdaptor.log(LogService.LOG_INFO,"Start failed, no server target server has been set",null);
+ }
+ }
+
+
+ /**
+ * Restarts the server. Useful when changing the Server parameters
+ *
+ * @deprecated as of RC 1
+ */
+ public void restart()
+ throws IOException
+ {
+ stop();
+ start();
+ }
+
+
+ /**
+ * Stops the HTTP daemon
+ */
+ public void stop()
+ {
+ try
+ {
+ if (alive)
+ {
+ alive = false;
+ // force the close with a socket call
+ new Socket(host, port);
+ }
+ }
+ catch (IOException e)
+ {
+ HttpAdaptor.log(LogService.LOG_WARNING,e.getMessage(),e);
+ }
+ try {
+ if (serverSocket != null)
+ {
+ serverSocket.close();
+ }
+ }
+ catch (IOException e)
+ {
+ HttpAdaptor.log(LogService.LOG_WARNING,e.getMessage(),e);
+ }
+ }
+
+
+ /**
+ * Adds an authorization pair as username/password
+ */
+ public void addAuthorization(String username, String password)
+ {
+ if (username == null || password == null)
+ {
+ throw new IllegalArgumentException("username and passwords cannot be null");
+ }
+ authorizations.put(username, password);
+ }
+
+
+ /**
+ * Gathers some basic data
+ */
+ public ObjectName preRegister(MBeanServer server, ObjectName name)
+ throws java.lang.Exception
+ {
+ this.server = server;
+ buildCommands();
+ return name;
+ }
+
+
+ public void postRegister(Boolean registrationDone) { }
+
+
+ public void preDeregister()
+ throws java.lang.Exception
+ {
+ // stop the server
+ stop();
+ }
+
+ public void postDeregister() { }
+
+ private ServerSocket createServerSocket() throws IOException
+ {
+ if (socketFactory == null)
+ {
+ if (factoryName == null)
+ {
+ socketFactory = new PlainAdaptorServerSocketFactory();
+ return socketFactory.createServerSocket(port, 50, host);
+ }
+ else
+ {
+ try
+ {
+ return (ServerSocket)server.invoke(factoryName, "createServerSocket", new Object[] {new Integer(port), new Integer(50), host}, new String[] {"int", "int", "java.lang.String"});
+ }
+ catch (Exception x)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,"Exception invoking AdaptorServerSocketFactory via MBeanServer", x);
+ }
+ }
+ }
+ else
+ {
+ return socketFactory.createServerSocket(port, 50, host);
+ }
+
+ return null;
+ }
+
+
+ private boolean isUsernameValid(String username, String password)
+ {
+ if (authorizations.containsKey(username))
+ {
+ return password.equals(authorizations.get(username));
+ }
+ return false;
+ }
+
+
+ protected HttpCommandProcessor getProcessor(String path)
+ {
+ return (HttpCommandProcessor)commands.get(path);
+ }
+
+
+ /**
+ * Build the commands
+ */
+ protected void buildCommands()
+ {
+ try
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ builder = factory.newDocumentBuilder();
+ for (int i=0;i<defaultCommandProcessors.length;i++)
+ {
+ try
+ {
+ HttpCommandProcessor processor = (HttpCommandProcessor)Class.forName(defaultCommandProcessors[i][1]).newInstance();
+ commands.put(defaultCommandProcessors[i][0], processor);
+ } catch (Exception e) {
+ HttpAdaptor.log(LogService.LOG_WARNING,"Exception building command procesor", e);
+ }
+ }
+ }
+ catch (ParserConfigurationException e)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,"Exception building the Document Factories", e);
+ }
+ }
+
+
+ protected void postProcess(HttpOutputStream out, HttpInputStream in, Document document)
+ throws IOException, JMException
+ {
+ boolean processed = false;
+ // inefficient but handles modifications at runtime
+ if (processorName != null)
+ {
+ if (server.isRegistered(processorName) &&
+ server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
+ {
+ server.invoke(processorName,
+ "writeResponse",
+ new Object[]{out, in, document},
+ new String[]{"mx4j.tools.adaptor.http.HttpOutputStream", "mx4j.tools.adaptor.http.HttpInputStream", "org.w3c.dom.Document"});
+ processed = true;
+ }
+ else
+ {
+ HttpAdaptor.log(LogService.LOG_DEBUG,processorName + " not found",null);
+ }
+ }
+ if (!processed && processor != null)
+ {
+ processor.writeResponse(out, in, document);
+ processed = true;
+ }
+ if (!processed)
+ {
+ defaultProcessor.writeResponse(out, in, document);
+ }
+ }
+
+
+ protected void findUnknownElement(String path, HttpOutputStream out, HttpInputStream in)
+ throws IOException, JMException
+ {
+ boolean processed = false;
+ // inefficient but handles modifications at runtime
+ if (processorName != null)
+ {
+ if (server.isRegistered(processorName) &&
+ server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
+ {
+ server.invoke(processorName,
+ "notFoundElement",
+ new Object[]{path, out, in},
+ new String[]{"java.lang.String", "mx4j.tools.adaptor.http.HttpOutputStream", "mx4j.tools.adaptor.http.HttpInputStream"});
+ processed = true;
+ }
+ else
+ {
+ HttpAdaptor.log(LogService.LOG_DEBUG,processorName + " not found",null);
+ }
+ }
+ if (!processed && processor != null)
+ {
+ processor.notFoundElement(path, out, in);
+ processed = true;
+ }
+ if (!processed)
+ {
+ defaultProcessor.notFoundElement(path, out, in);
+ }
+ }
+
+
+ protected String preProcess(String path)
+ throws IOException, JMException
+ {
+ boolean processed = false;
+ // inefficient but handles modifications at runtime
+ if (processorName != null)
+ {
+ HttpAdaptor. log(LogService.LOG_DEBUG,"Preprocess using " + processorName,null);
+ if (server.isRegistered(processorName) &&
+ server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
+ {
+ HttpAdaptor.log(LogService.LOG_DEBUG,"Preprocessing",null);
+ path = (String)server.invoke(processorName,
+ "preProcess",
+ new Object[]{path},
+ new String[]{"java.lang.String"});
+ processed = true;
+ }
+ else
+ {
+ HttpAdaptor.log(LogService.LOG_DEBUG,processorName + " not found",null);
+ }
+ }
+ if (!processed && processor != null)
+ {
+ path = processor.preProcess(path);
+ processed = true;
+ }
+ if (!processed)
+ {
+ path = defaultProcessor.preProcess(path);
+ }
+ return path;
+ }
+
+
+ protected void postProcess(HttpOutputStream out, HttpInputStream in, Exception e)
+ throws IOException, JMException
+ {
+ boolean processed = false;
+ // inefficient but handles modifications at runtime
+ if (processorName != null)
+ {
+ if (server.isRegistered(processorName) &&
+ server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
+ {
+ server.invoke(processorName,
+ "writeError",
+ new Object[]{out, in, e},
+ new String[]{"mx4j.tools.adaptor.http.HttpOutputStream", "mx4j.tools.adaptor.http.HttpInputStream", "java.lang.Exception"});
+ processed = true;
+ }
+ else
+ {
+ HttpAdaptor.log(LogService.LOG_DEBUG,processorName + " not found",null);
+ }
+ }
+ if (!processed && processor != null)
+ {
+ processor.writeError(out, in, e);
+ processed = true;
+ }
+ if (!processed)
+ {
+ defaultProcessor.writeError(out, in, e);
+ }
+ }
+
+
+ private class HttpClient extends Thread
+ {
+ private Socket client;
+
+
+ HttpClient(Socket client)
+ {
+ this.client = client;
+ }
+
+ public boolean isValid(String authorizationString) {
+ if (authenticationMethod.startsWith("basic"))
+ {
+ authorizationString = authorizationString.substring(5,authorizationString.length());
+ String decodeString = new String(Base64Codec.decodeBase64(authorizationString.getBytes()));
+ if (decodeString.indexOf(":")>0)
+ {
+ try
+ {
+ StringTokenizer tokens = new StringTokenizer(decodeString, ":");
+ String username = tokens.nextToken();
+ String password = tokens.nextToken();
+ return isUsernameValid(username, password);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ private boolean handleAuthentication(HttpInputStream in, HttpOutputStream out) throws IOException {
+ if (authenticationMethod.equals("basic"))
+ {
+ String result = in.getHeader("authorization");
+ if (result != null)
+ {
+ if (isValid(result))
+ {
+ return true;
+ }
+ throw new HttpException(HttpConstants.STATUS_FORBIDDEN, "Authentication failed");
+ }
+
+ out.setCode(HttpConstants.STATUS_AUTHENTICATE);
+ out.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
+ out.sendHeaders();
+ out.flush();
+ return false;
+ }
+ if (authenticationMethod.equals("digest"))
+ {
+ // not implemented
+ }
+ return true;
+ }
+
+
+ public void run()
+ {
+ HttpInputStream httpIn = null;
+ HttpOutputStream httpOut = null;
+ try
+ {
+ // get input streams
+ InputStream in = client.getInputStream();
+ httpIn = new HttpInputStream(in);
+ httpIn.readRequest();
+
+ // Find a suitable command processor
+ String path = httpIn.getPath();
+ String queryString = httpIn.getQueryString();
+ HttpAdaptor.log(LogService.LOG_INFO,"Request " + path + ((queryString == null) ? "" : ("?" + queryString)), null);
+ String postPath = preProcess(path);
+ if (!postPath.equals(path))
+ {
+ HttpAdaptor.log(LogService.LOG_INFO,"Processor replaced path " + path + " with the path " + postPath,null);
+ path = postPath;
+ }
+ OutputStream out = client.getOutputStream();
+ httpOut = new HttpOutputStream(out, httpIn);
+ if (!handleAuthentication(httpIn, httpOut)) {
+ return;
+ }
+ HttpCommandProcessor processor = getProcessor(path.substring(1, path.length()));
+ if (processor == null)
+ {
+ HttpAdaptor.log(LogService.LOG_INFO,"No suitable command processor found, requesting from processor path " + path, null);
+ findUnknownElement(path, httpOut, httpIn);
+ }
+ else
+ {
+ Document document = processor.executeRequest(httpIn);
+ postProcess(httpOut, httpIn, document);
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ HttpAdaptor.log(LogService.LOG_WARNING,"Exception during http request", ex);
+ if (httpOut != null)
+ {
+ try
+ {
+ postProcess(httpOut, httpIn, ex);
+ }
+ catch (IOException e)
+ {
+ HttpAdaptor.log(LogService.LOG_WARNING,"IOException during http request", e);
+ }
+ catch (JMException e)
+ {
+ HttpAdaptor.log(LogService.LOG_WARNING,"JMException during http request", e);
+ }
+ catch (RuntimeException rte)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,"RuntimeException during http request", rte);
+ }
+ catch (Error er)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,"Error during http request ", er);
+ }
+ catch (Throwable t)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,"Throwable during http request ", t);
+ }
+ }
+ }
+ catch (Error ex)
+ {
+ HttpAdaptor.log(LogService.LOG_ERROR,"Error during http request ", ex);
+ }
+ finally
+ {
+ try
+ {
+ if (httpOut != null)
+ {
+ httpOut.flush();
+ }
+ // always close the socket
+ client.close();
+ }
+ catch (IOException e)
+ {
+ HttpAdaptor.log(LogService.LOG_WARNING,"Exception during request processing", e);
+ }
+ }
+ }
+ }
+
+
+ private static void log(int prio, String message, Throwable t){
+ if (HttpConnectorActivator.bc!=null){
+ ServiceReference logSR=HttpConnectorActivator.bc.getServiceReference(LogService.class.getName());
+ if (logSR!=null){
+ ((LogService)HttpConnectorActivator.bc.getService(logSR)).log(prio, message, t);
+ }else{
+ System.out.println("No Log Service");
+ }
+ }else{
+ System.out.println("mx4j.tools.adapatoir.http.HttpAdaptor.log: No bundleContext");
+ }
+ }
+}
+
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptorMBean.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptorMBean.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptorMBean.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpAdaptorMBean.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+import java.util.Date;
+import java.io.IOException;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.AdaptorServerSocketFactory;
+
+/**
+ * Management interface for the HttpAdaptor MBean.
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface HttpAdaptorMBean
+{
+ /**
+ * Sets the value of the server's port
+ * @param port the new port's value
+ */
+ public void setPort(int port);
+
+ /**
+ * Returns the port where the server is running on. Default is 8080
+ * @return HTTPServer's port
+ */
+ public int getPort();
+
+ /**
+ * Sets the host name where the server will be listening
+ * @param host Server's host
+ */
+ public void setHost(java.lang.String host);
+
+ /**
+ * Return the host name the server will be listening to. If null the server listen at the localhost
+ * @return the current hostname
+ */
+ java.lang.String getHost();
+
+ /**
+ * Sets the Authentication Method.
+ * @param method none/basic/digest
+ */
+ public void setAuthenticationMethod(String method);
+
+ /**
+ * Authentication Method
+ * @return authentication method
+ */
+ public String getAuthenticationMethod();
+
+ /**
+ * Sets the object which will post process the XML results.
+ * The last value set between the setPostProcessor and setPostProcessorName will be the valid one
+ * @param processor a Post processor object
+ */
+ public void setProcessor(ProcessorMBean processor);
+
+ /**
+ * Returns the Processor set by {@link #setProcessor}
+ */
+ public ProcessorMBean getProcessor();
+
+ /**
+ * Sets the classname of the object which will post process the XML results.
+ * The adaptor will try to build the object and use the processor name ObjectName to register it.
+ * The class name has to implements mx4j.tools.adaptor.http.ProcessorMBean and be MBean compliant
+ * @param processorClass a Post processor object
+ */
+ public void setProcessorClass(String processorClass);
+
+ /**
+ * Sets the object name of the PostProcessor MBean. If ProcessorClass is set the processor will be created
+ * @param processorName a Post processor object
+ */
+ public void setProcessorNameString(String processorName) throws MalformedObjectNameException;
+
+ /**
+ * Sets the object name which will post process the XML result. The last value set between the setPostProcessor and setPostProcessorName will be the valid one. The MBean will be verified to be of instance HttpPostProcessor
+ * @param processorName The new processorName value
+ */
+ public void setProcessorName(ObjectName processorName);
+
+ /**
+ * Returns the ObjectName of the processor set by {@link #setProcessorName}
+ */
+ public ObjectName getProcessorName();
+
+ /**
+ * Sets the object which create the server sockets
+ * @param factory the socket factory
+ */
+ public void setSocketFactory(AdaptorServerSocketFactory factory);
+
+ /**
+ * Sets the factory's object name which will create the server sockets
+ * @param factoryName the socket factory
+ */
+ public void setSocketFactoryName(ObjectName factoryName);
+
+ /**
+ * Sets the factory's object name which will create the server sockets
+ * @param factoryName the socket factory
+ */
+ public void setSocketFactoryNameString(String factoryName) throws MalformedObjectNameException;
+
+ /**
+ * Indicates whether the server's running
+ * @return The active value
+ */
+ public boolean isActive();
+
+ /**
+ * Starting date
+ * @return The date when the server was started
+ */
+ public Date getStartDate();
+
+ /**
+ * Requests count
+ * @return The total of requests served so far
+ */
+ public long getRequestsCount();
+
+ /**
+ * Gets the HttpAdaptor version
+ * @return HttpAdaptor's version
+ */
+ public String getVersion();
+
+ /**
+ * Adds a command processor object
+ */
+ public void addCommandProcessor(String path, HttpCommandProcessor processor);
+
+ /**
+ * Adds a command processor object by class
+ */
+ public void addCommandProcessor(String path, String processorClass);
+
+ /**
+ * Removes a command processor object by class
+ */
+ public void removeCommandProcessor(String path);
+
+ /**
+ * Starts the server
+ */
+ public void start() throws IOException;
+
+ /**
+ * Stops the HTTP daemon
+ */
+ public void stop();
+
+ /**
+ * Adds an authorization pair as username/password
+ */
+ public void addAuthorization(String username, String password);
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessor.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessor.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+
+import java.io.IOException;
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.xml.parsers.DocumentBuilder;
+
+import org.w3c.dom.Document;
+
+/**
+ * HttpCommandProcessor sets the structure of a command processor
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+
+public interface HttpCommandProcessor
+{
+
+ /**
+ * Executes an HTTP request. It assumes the request is well formed
+ *
+ * @param out Input request
+ * @return An XML Document
+ * @exception IOException
+ */
+ public Document executeRequest(HttpInputStream in) throws IOException, JMException;
+
+ /**
+ * Sets the target MBeanServer
+ */
+ public void setMBeanServer(MBeanServer server);
+
+ /**
+ * Sets the Document Builder factory
+ */
+ public void setDocumentBuilder(DocumentBuilder builder);
+
+}
+
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessorAdaptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessorAdaptor.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessorAdaptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpCommandProcessorAdaptor.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+
+import java.io.IOException;
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.xml.parsers.DocumentBuilder;
+import org.w3c.dom.Document;
+
+/**
+ * HttpCommandProcessor sets the structure of a command processor
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public abstract class HttpCommandProcessorAdaptor implements HttpCommandProcessor
+{
+ protected MBeanServer server;
+
+ protected DocumentBuilder builder;
+
+ public abstract Document executeRequest(HttpInputStream in) throws IOException, JMException;
+
+ /**
+ * Sets the target MBeanServer
+ */
+ public void setMBeanServer(MBeanServer server) {
+ this.server = server;
+ }
+
+ /**
+ * Sets the Document Builder factory
+ */
+ public void setDocumentBuilder(DocumentBuilder builder) {
+ this.builder = builder;
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpConstants.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpConstants.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpConstants.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpConstants.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+/**
+ * Define constants for the HTTP request processing
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class HttpConstants
+{
+ /**
+ * Server info header
+ */
+ public final static String SERVER_INFO = "MX4J-HTTPD/1.0";
+
+ /**
+ * HTTP implemented version
+ */
+ public final static String HTTP_VERSION = "HTTP/1.0 ";
+
+ /**
+ * Get method header
+ */
+ public final static String METHOD_GET = "GET";
+
+ /**
+ * Post method header
+ */
+ public final static String METHOD_POST = "POST";
+
+ /**
+ * Status code OK
+ */
+ public final static int STATUS_OKAY = 200;
+
+ /**
+ * Status code NO CONTENT
+ */
+ public final static int STATUS_NO_CONTENT = 204;
+
+ /**
+ * Status code MOVED PERMANENTLY
+ */
+ public final static int STATUS_MOVED_PERMANENTLY = 301;
+
+ /**
+ * Status code MOVED TEMPORARILY
+ */
+ public final static int STATUS_MOVED_TEMPORARILY = 302;
+
+ /**
+ * Status code BAD REQUEST
+ */
+ public final static int STATUS_BAD_REQUEST = 400;
+
+ /**
+ * Status code AUTHENTICATE
+ */
+ public final static int STATUS_AUTHENTICATE = 401;
+
+ /**
+ * Status code FORBIDDEN
+ */
+ public final static int STATUS_FORBIDDEN = 403;
+
+ /**
+ * Status code NOT FOUND
+ */
+ public final static int STATUS_NOT_FOUND = 404;
+
+ /**
+ * Status code NOT ALLOWED
+ */
+ public final static int STATUS_NOT_ALLOWED = 405;
+
+ /**
+ * Status code INTERNAL ERROR
+ */
+ public final static int STATUS_INTERNAL_ERROR = 500;
+
+ /**
+ * Status code NOT IMPLEMENTED
+ */
+ public final static int STATUS_NOT_IMPLEMENTED = 501;
+
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpException.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpException.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpException.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpException.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+
+import java.io.IOException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ * HttpException is emitted when an error parsing an HTTP request appears
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+
+public class HttpException extends IOException
+{
+ /** Error code */
+ protected int code;
+
+ /**
+ * Constructor for the HttpException object
+ *
+ * @param code Error code
+ * @param description Description
+ */
+
+ public HttpException(int code, String description)
+ {
+ super(description);
+ this.code = code;
+ }
+
+ /**
+ * Return the exception code
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ public Document getResponseDoc() {
+ try
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+ Element root = document.createElement("HttpException");
+ root.setAttribute("code", Integer.toString(code));
+ root.setAttribute("description", getMessage());
+ document.appendChild(root);
+ return document;
+ }
+ catch (ParserConfigurationException e)
+ {
+ return null;
+ }
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpInputStream.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpInputStream.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpInputStream.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpInputStream.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.NoSuchElementException;
+import java.net.URLDecoder;
+
+/**
+ * HttpInputStream processes an HTTP request
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+
+public class HttpInputStream extends BufferedInputStream {
+ /** Http method. only GET, POST implemented */
+ private String method;
+
+ /** Path of the request */
+ private String path;
+
+ /** Query string */
+ private String queryString;
+
+ /** Request version */
+ private float version;
+
+ /** Current headers */
+ private Map headers = new HashMap();
+
+ private Map variables = new HashMap();
+
+ /**
+ * Constructs a new HttpInputStream
+ *
+ * @param in InputStream
+ */
+ public HttpInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ /**
+ * Returns the method of the request
+ *
+ * @return the method of the request GET/POST
+ */
+ public String getMethod()
+ {
+ return method;
+ }
+
+ /**
+ * Returns the path of the request
+ *
+ * @return the path of the request
+ */
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ /**
+ * Returns the query string
+ *
+ * @return The queryString value
+ */
+ public String getQueryString()
+ {
+ return queryString;
+ }
+
+ /**
+ * Returns the version of the request
+ *
+ * @return The version value 1.0/1.1
+ */
+ public float getVersion()
+ {
+ return version;
+ }
+
+ /**
+ * Returns a given header by name, assumes lower case
+ *
+ * @param name Name of the header
+ * @return The header value
+ */
+ public String getHeader(String name)
+ {
+ return (String) headers.get(name);
+ }
+
+ /**
+ * Returns a given header by name, assumes lower case
+ *
+ * @param name Name of the header
+ * @return The header value
+ */
+ public Map getHeaders()
+ {
+ return headers;
+ }
+
+ /**
+ * Reads the request parsing the headers
+ *
+ * @exception IOException Description of Exception
+ */
+ public void readRequest() throws IOException
+ {
+ String request = readLine();
+ if (request == null)
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, "Null query");
+ }
+ // Parses the request
+ StringTokenizer parts = new StringTokenizer(request);
+ try
+ {
+ parseMethod(parts.nextToken());
+ parseRequest(parts.nextToken());
+ }
+ catch (NoSuchElementException ex)
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, request);
+ }
+ if (parts.hasMoreTokens())
+ {
+ parseVersion(parts.nextToken());
+ }
+ else
+ {
+ version = 0.9f;
+ }
+ if (version >= 1.0f)
+ {
+ readHeaders();
+ parseVariables();
+ }
+ }
+
+ /**
+ * Reads an HTTP line
+ *
+ * @return A read line
+ * @exception IOException Emmited in case of errors reading the stream
+ */
+ public String readLine() throws IOException
+ {
+ StringBuffer line = new StringBuffer(64);
+ line.delete(0, line.length());
+ int c;
+ while (((c = read()) != -1) && (c != '\n') && (c != '\r'))
+ {
+ line.append((char) c);
+ }
+ if ((c == '\r') && ((c = read()) != '\n') && (c != -1))
+ {
+ --pos;
+ }
+ if ((c == -1) && (line.length() == 0))
+ {
+ return null;
+ }
+ else
+ {
+ return line.toString();
+ }
+ }
+
+ /**
+ * Returns a map with the variables passed in the request.
+ *
+ * @return A map containing variables/value pairs. If a variable is
+ * present only once in the request the value will be a String.
+ * If it is present many times the variable will be a String[]
+ */
+ public Map getVariables()
+ {
+ return variables;
+ }
+ /**
+ * Returns one variable value. If the variable is present many times, the first
+ * instance will be returned
+ *
+ * @return A String with the variable value
+ */
+ public String getVariable(String name)
+ {
+ if (variables.containsKey(name))
+ {
+ Object variable = variables.get(name);
+ if (variable instanceof String)
+ {
+ return (String)variable;
+ }
+ else if (variable instanceof String[])
+ {
+ return ((String[])variable)[0];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns one variable values.
+ *
+ * @return A String array with all variable instances
+ */
+ public String[] getVariableValues(String name)
+ {
+ if (variables.containsKey(name))
+ {
+ Object variable = variables.get(name);
+ if (variable instanceof String[])
+ {
+ return (String[])variable;
+ } else if (variable instanceof String)
+ {
+ String[] result = new String[1];
+ result[0] = (String)variable;
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parses the request parameters
+ */
+ protected void parseVariables() throws HttpException
+ {
+ try
+ {
+ // get request variables
+ String variableHolder = "";
+ if (method.equals(HttpConstants.METHOD_POST) && "application/x-www-form-urlencoded".equals(headers.get("content-type"))
+ && (headers.get("content-length") != null))
+ {
+ if ("chunked".equals(headers.get("transfer-encoding")))
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, "Sorry I don't understand chunked requests");
+ }
+ StringBuffer buffer = new StringBuffer();
+ int size = Integer.parseInt((String)headers.get("content-length"));
+ mark(size);
+ for (int i=0;i<size;i++)
+ {
+ int j=read();
+ if (j>=0)
+ {
+ buffer.append((char)j);
+ }
+ else
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, "Request not understood");
+ }
+ }
+ variableHolder = buffer.toString();
+ reset();
+ }
+ else if (method.equals(HttpConstants.METHOD_GET))
+ {
+ variableHolder = getQueryString();
+ }
+ else
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, "Request not understood");
+ }
+ StringTokenizer parser = new StringTokenizer(variableHolder, "&");
+ while (parser.hasMoreTokens())
+ {
+ String command = parser.nextToken();
+ int equalIndex = command.indexOf('=');
+ if (equalIndex > 0)
+ {
+ String variableName = URLDecoder.decode(command.substring(0, equalIndex));
+ String variableValue = URLDecoder.decode(command.substring(equalIndex + 1, command.length()));
+ variableValue = new String(variableValue.getBytes(), "UTF-8");
+ if (variables.get(variableName) != null) {
+ Object value = variables.get(variableName);
+ String[] newValue = null;
+ if (value instanceof String)
+ {
+ newValue = new String[2];
+ newValue[0] = variableValue;
+ newValue[1] = (String)value;
+ }
+ else
+ {
+ String[] oldValue = (String[])value;
+ newValue = new String[oldValue.length+1];
+ System.arraycopy(oldValue, 0, newValue, 1, oldValue.length);
+ newValue[0] = variableValue;
+ }
+ variables.put(variableName, newValue);
+ }
+ else
+ {
+ variables.put(variableName, variableValue);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, getQueryString());
+ }
+ }
+
+ /**
+ * Parses the connection method. GET/POST are allowed
+ *
+ * @param method Description of Parameter
+ * @exception HttpException Description of Exception
+ */
+ protected void parseMethod(String method) throws HttpException
+ {
+ if (method.equals(HttpConstants.METHOD_GET))
+ {
+ this.method = HttpConstants.METHOD_GET;
+ }
+ else if (method.equals(HttpConstants.METHOD_POST))
+ {
+ this.method = HttpConstants.METHOD_POST;
+ }
+ else
+ {
+ throw new HttpException(HttpConstants.STATUS_NOT_IMPLEMENTED, method);
+ }
+ }
+
+ /**
+ * Parses the request
+ *
+ * @param request Request string
+ * @exception HttpException Thrown if an error ocurr
+ */
+ protected void parseRequest(String request) throws HttpException
+ {
+ if (!request.startsWith("/"))
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, request);
+ }
+ int queryIdx = request.indexOf('?');
+ if (queryIdx == -1)
+ {
+ path = HttpUtil.canonicalizePath(request);
+ queryString = "";
+ }
+ else
+ {
+ path = HttpUtil.canonicalizePath(request.substring(0, queryIdx));
+ queryString = request.substring(queryIdx + 1);
+ }
+ }
+
+ /**
+ * Parses the request HttpConstants version
+ *
+ * @param verStr String containing the HTTP version
+ * @exception HttpException
+ */
+ protected void parseVersion(String verStr) throws HttpException
+ {
+ if (!verStr.startsWith("HTTP/"))
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, verStr);
+ }
+ try
+ {
+ version = Float.valueOf(verStr.substring(5)).floatValue();
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new HttpException(HttpConstants.STATUS_BAD_REQUEST, verStr);
+ }
+ }
+
+ /**
+ * Reads the headers
+ *
+ * @exception IOException
+ */
+ protected void readHeaders() throws IOException
+ {
+ String header;
+ while (((header = readLine()) != null) && !header.equals(""))
+ {
+ int colonIdx = header.indexOf(':');
+ {
+ String name = header.substring(0, colonIdx);
+ String value = header.substring(colonIdx + 1);
+ headers.put(name.toLowerCase(), value.trim());
+ }
+ }
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpOutputStream.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpOutputStream.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpOutputStream.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpOutputStream.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+import java.io.BufferedOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * HttpAdaptor sets the basic adaptor listening for HTTP requests
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class HttpOutputStream extends BufferedOutputStream
+{
+ /** Answer code */
+ protected int code;
+ /** whether to send the headers*/
+ protected boolean sendHeaders;
+ /** Headers to be sent */
+ protected Map headers = new HashMap(7);
+ /**
+ * Creates a new HttpOutputStream with a given OutputStream and an InputStream
+ *
+ * @param out The OutputStream normally associated with the output socket
+ * stream of the incoming connection
+ * @param in HttpInputStream containing the incoming request
+ */
+ public HttpOutputStream(OutputStream out, HttpInputStream in)
+ {
+ super(out);
+ code = HttpConstants.STATUS_OKAY;
+ setHeader("Server", HttpConstants.SERVER_INFO);
+ sendHeaders = (in.getVersion() >= 1.0);
+ }
+ /**
+ * Sets the answer code
+ *
+ * @param code The new code value
+ */
+ public void setCode(int code)
+ {
+ this.code = code;
+ }
+ /**
+ * Sets a given header code
+ *
+ * @param attr The new header name
+ * @param value The new header value
+ */
+ public void setHeader(String attr, String value)
+ {
+ headers.put(attr, value);
+ }
+ /**
+ * Sends the headers
+ *
+ * @return Description of the Returned Value
+ * @exception IOException Description of Exception
+ */
+ public boolean sendHeaders() throws IOException
+ {
+ if (sendHeaders)
+ {
+ StringBuffer buffer = new StringBuffer(512);
+ buffer.append(HttpConstants.HTTP_VERSION);
+ buffer.append(code);
+ buffer.append(" ");
+ buffer.append(HttpUtil.getCodeMessage(code));
+ buffer.append("\r\n");
+ Iterator attrs = headers.keySet().iterator();
+ int size = headers.size();
+ for (int i = 0; i < size; i++)
+ {
+ String attr = (String) attrs.next();
+ buffer.append(attr);
+ buffer.append(": ");
+ buffer.append(headers.get(attr));
+ buffer.append("\r\n");
+ }
+ buffer.append("\r\n");
+ write(buffer.toString());
+ }
+ return sendHeaders;
+ }
+ /**
+ * Writes a given message line
+ *
+ * @param msg The message to be written
+ * @exception IOException
+ */
+ public void write(String msg) throws IOException
+ {
+ write(msg.getBytes("latin1"));
+ }
+ /**
+ * Writes the content of the input stream to the output stream
+ *
+ * @param in The input stream
+ * @exception IOException
+ */
+ public void write(InputStream in) throws IOException
+ {
+ int n;
+ int length = buf.length;
+ while ((n = in.read(buf, count, length - count)) >= 0)
+ {
+ if ((count += n) >= length)
+ {
+ out.write(buf, count = 0, length);
+ }
+ }
+ }
+}
+
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpUtil.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpUtil.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpUtil.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/HttpUtil.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+/**
+ * Utility methods for the HTTP adaptor
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class HttpUtil
+{
+
+ /**
+ * Gets a message apropriate for a give HTTP code
+ *
+ * @param code Reference Code
+ * @return The result message
+ * @see HttpConstants
+ */
+ public static String getCodeMessage(int code) {
+ switch (code) {
+ case HttpConstants.STATUS_OKAY:
+ return "OK";
+ case HttpConstants.STATUS_NO_CONTENT:
+ return "No Content";
+ case HttpConstants.STATUS_MOVED_PERMANENTLY:
+ return "Moved Permanently";
+ case HttpConstants.STATUS_MOVED_TEMPORARILY:
+ return "Moved Temporarily";
+ case HttpConstants.STATUS_BAD_REQUEST:
+ return "Bad Request";
+ case HttpConstants.STATUS_FORBIDDEN:
+ return "Forbidden";
+ case HttpConstants.STATUS_NOT_FOUND:
+ return "Not Found";
+ case HttpConstants.STATUS_NOT_ALLOWED:
+ return "Method Not Allowed";
+ case HttpConstants.STATUS_INTERNAL_ERROR:
+ return "Internal Server Error";
+ case HttpConstants.STATUS_AUTHENTICATE:
+ return "Authentication requested";
+ case HttpConstants.STATUS_NOT_IMPLEMENTED:
+ return "Not Implemented";
+ default:
+ return "Unknown Code (" + code + ")";
+ }
+ }
+
+
+ /**
+ * Makes a path canonical
+ *
+ * @param path Target path
+ * @return The canonicalized path
+ */
+ public static String canonicalizePath(String path) {
+ char[] chars = path.toCharArray();
+ int length = chars.length;
+ int idx;
+ int odx = 0;
+ while ((idx = indexOf(chars, length, '/', odx)) < length - 1)
+ {
+ int ndx = indexOf(chars, length, '/', idx + 1);
+ int kill = -1;
+ if (ndx == idx + 1)
+ {
+ kill = 1;
+ }
+ else if ((ndx >= idx + 2) && (chars[idx + 1] == '.'))
+ {
+ if (ndx == idx + 2)
+ {
+ kill = 2;
+ }
+ else if ((ndx == idx + 3) && (chars[idx + 2] == '.'))
+ {
+ kill = 3;
+ while ((idx > 0) && (chars[--idx] != '/'))
+ {
+ ++kill;
+ }
+ }
+ }
+ if (kill == -1)
+ {
+ odx = ndx;
+ }
+ else if (idx + kill >= length)
+ {
+ length = odx = idx + 1;
+ }
+ else
+ {
+ length -= kill;
+ System.arraycopy(chars, idx + 1 + kill,
+ chars, idx + 1, length - idx - 1);
+ odx = idx;
+ }
+ }
+ return new String(chars, 0, length);
+ }
+
+
+ protected static int indexOf(char[] chars, int length, char chr, int from)
+ {
+ while ((from < length) && (chars[from] != chr))
+ {
+ ++from;
+ }
+ return from;
+ }
+
+ /**
+ * Returns whether a boolean variable is in the variables. It tries to find
+ * it. If not found the the default is used. If found is tested to check if
+ * it is <code>true</code> or <code>1</code> and the answer is true.
+ * Otherwise is false
+ */
+ public static boolean booleanVariableValue(HttpInputStream in, String variable, boolean defaultValue)
+ {
+ if (in.getVariables().containsKey(variable))
+ {
+ String result = (String)in.getVariables().get(variable);
+ return result.equals("true") || result.equals("1");
+ }
+ return defaultValue;
+ }
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/InvokeOperationCommandProcessor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/InvokeOperationCommandProcessor.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/InvokeOperationCommandProcessor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/InvokeOperationCommandProcessor.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MalformedObjectNameException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * InvokeOperationCommandProcessor, processes a request for unregistering an MBean
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class InvokeOperationCommandProcessor extends HttpCommandProcessorAdaptor
+{
+ public InvokeOperationCommandProcessor()
+ {
+ }
+
+ public Document executeRequest(HttpInputStream in) throws IOException, JMException
+ {
+ Document document = builder.newDocument();
+
+ Element root = document.createElement("MBeanOperation");
+ document.appendChild(root);
+ Element operationElement = document.createElement("Operation");
+ operationElement.setAttribute("operation", "invoke");
+ root.appendChild(operationElement);
+
+ String objectVariable = in.getVariable("objectname");
+ String operationVariable = in.getVariable("operation");
+ if (objectVariable == null || objectVariable.equals("")
+ || operationVariable == null || operationVariable.equals(""))
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", "Incorrect parameters in the request");
+ return document;
+ }
+ operationElement.setAttribute("objectname", objectVariable);
+ List types = new ArrayList();
+ List values = new ArrayList();
+ int i=0;
+ boolean unmatchedParameters = false;
+ boolean valid = false;
+ do
+ {
+ String parameterType = in.getVariable("type"+i);
+ String parameterValue = in.getVariable("value"+i);
+ valid = (parameterType != null && parameterValue != null);
+ if (valid)
+ {
+ types.add(parameterType);
+ Object value = null;
+ try
+ {
+ value = CommandProcessorUtil.createParameterValue(parameterType, parameterValue);
+ }
+
+ catch (Exception e)
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", "Parameter " + i + ": " + parameterValue + " cannot be converted to type " + parameterType);
+ return document;
+ }
+ if (value != null)
+ {
+ values.add(value);
+ }
+ }
+ if (parameterType == null ^ parameterValue == null)
+ {
+ unmatchedParameters = true;
+ break;
+ }
+ i++;
+ }
+ while (valid);
+ if (objectVariable == null || objectVariable.equals("") ||
+ operationVariable == null || operationVariable.equals(""))
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", "Incorrect parameters in the request");
+ return document;
+ }
+ if (unmatchedParameters)
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", "count of parameter types doesn't match count of parameter values");
+ return document;
+ }
+ ObjectName name = null;
+ try
+ {
+ name = new ObjectName(objectVariable);
+ }
+ catch (MalformedObjectNameException e)
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", "Malformed object name");
+ return document;
+ }
+
+ if (server.isRegistered(name))
+ {
+ MBeanInfo info = server.getMBeanInfo(name);
+ MBeanOperationInfo[] operations = info.getOperations();
+ boolean match = false;
+ if (operations != null)
+ {
+ for (int j=0;j<operations.length;j++)
+ {
+ if (operations[j].getName().equals(operationVariable))
+ {
+ MBeanParameterInfo[] parameters = operations[j].getSignature();
+ if (parameters.length != types.size())
+ {
+ continue;
+ }
+ Iterator k = types.iterator();
+ boolean signatureMatch = true;
+ for (int p = 0;p<types.size();p++)
+ {
+ if (!parameters[p].getType().equals(k.next()))
+ {
+ signatureMatch = false;
+ break;
+ }
+ }
+ match = signatureMatch;
+ }
+ if (match)
+ {
+ break;
+ }
+ }
+ }
+ if (!match)
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", "Operation singature has no match in the MBean");
+ }
+ else
+ {
+ try
+ {
+ Object[] params = values.toArray();
+ String[] signature = new String[types.size()];
+ types.toArray(signature);
+ Object returnValue = server.invoke(name, operationVariable, params, signature);
+ operationElement.setAttribute("result", "success");
+ if (returnValue != null)
+ {
+ operationElement.setAttribute("returnclass", returnValue.getClass().getName());
+ operationElement.setAttribute("return", returnValue.toString());
+ } else
+ {
+ operationElement.setAttribute("returnclass", null);
+ operationElement.setAttribute("return", null);
+ }
+ }
+ catch (Exception e)
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", e.getMessage());
+ }
+ }
+ }
+ else
+ {
+ if (name != null)
+ {
+ operationElement.setAttribute("result", "error");
+ operationElement.setAttribute("errorMsg", new StringBuffer("MBean ").append(name).append(" not registered").toString());
+ }
+ }
+ return document;
+ }
+
+}
Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/MBeanCommandProcessor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/MBeanCommandProcessor.java?rev=423855&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/MBeanCommandProcessor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.httpconnector/src/main/java/org/apache/felix/mosgi/jmx/httpconnector/mx4j/tools/adaptor/http/MBeanCommandProcessor.java Thu Jul 20 02:36:47 2006
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Comparator;
+import java.util.TreeSet;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ObjectName;
+//import javax.management.modelmbean.ModelMBeanInfo;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * MBeanCommandProcessor, processes a request for getting data about a MBean
+ *
+ * @author <a href="mailto:tibu@users.sourceforge.net">Carlos Quiroz</a>
+ * @author <a href="mailto:l.dobrev@lsnsoft.com">Lachezar Dobrev</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class MBeanCommandProcessor extends HttpCommandProcessorAdaptor
+{
+ public MBeanCommandProcessor()
+ {
+ }
+
+ public Document executeRequest(HttpInputStream in) throws IOException, JMException
+ {
+ Document document = builder.newDocument();
+
+ String name = in.getVariable("objectname");
+ ObjectName objectName = null;
+
+ if (name != null)
+ {
+ objectName = new ObjectName(name);
+ if (!objectName.isPattern())
+ {
+ // not a pattern - assume a single MBean
+ if (server.isRegistered(objectName))
+ {
+ Element mb = createMBeanElement(document, objectName, in);
+ document.appendChild(mb);
+ }
+ }
+ else
+ {
+ // A pattern - return all matching MBeans
+ Set names = new TreeSet(CommandProcessorUtil.createObjectNameComparator());
+ names.addAll(server.queryNames(objectName, null));
+ Element root = document.createElement("Server");
+ root.setAttribute("pattern", objectName.toString());
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ Element mb = createMBeanElement(document, (ObjectName)it.next(), in);
+ root.appendChild(mb);
+ }
+ document.appendChild(root);
+ }
+ }
+ return document;
+ }
+
+ private Element createMBeanElement(Document document, ObjectName objectName, HttpInputStream in)
+ throws JMException
+ {
+ Element root = document.createElement("MBean");
+
+ MBeanInfo info = server.getMBeanInfo(objectName);
+ root.setAttribute("description", info.getDescription());
+ root.setAttribute("classname", info.getClassName());
+ root.setAttribute("objectname", objectName.toString());
+/*
+ if (info instanceof ModelMBeanInfo)
+ {
+ root.setAttribute("model", "true");
+ }
+*/
+ if (HttpUtil.booleanVariableValue(in, "attributes", true)) {
+ MBeanAttributeInfo[] attributes = info.getAttributes();
+ if (attributes != null)
+ {
+ SortedMap sortedAttributes = new TreeMap();
+ for (int i=0;i<attributes.length;i++)
+ {
+ Element attribute = document.createElement("Attribute");
+ attribute.setAttribute("name", attributes[i].getName());
+ attribute.setAttribute("type", attributes[i].getType());
+ attribute.setAttribute("description", attributes[i].getDescription());
+ attribute.setAttribute("strinit", String.valueOf(CommandProcessorUtil.canCreateParameterValue(attributes[i].getType())));
+ if (attributes[i].isReadable() && attributes[i].isWritable())
+ {
+ attribute.setAttribute("availability", "RW");
+ }
+ if (attributes[i].isReadable() && !attributes[i].isWritable())
+ {
+ attribute.setAttribute("availability", "RO");
+ }
+ if (!attributes[i].isReadable() && attributes[i].isWritable())
+ {
+ attribute.setAttribute("availability", "WO");
+ }
+ try
+ {
+ Object attributeValue = server.getAttribute(objectName, attributes[i].getName());
+ attribute.setAttribute("isnull", (attributeValue==null)?"true":"false");
+ if (attributeValue != null)
+ {
+ attribute.setAttribute("value", attributeValue.toString());
+ if (attributeValue.getClass().isArray())
+ {
+ attribute.setAttribute("aggregation", "array");
+ }
+ if (attributeValue instanceof java.util.Collection)
+ {
+ attribute.setAttribute("aggregation", "collection");
+ }
+ if (attributeValue instanceof java.util.Map)
+ {
+ attribute.setAttribute("aggregation", "map");
+ }
+ }
+ else
+ {
+ attribute.setAttribute("value", "null");
+ }
+
+ }
+ catch (JMException e)
+ {
+ attribute.setAttribute("value", e.getMessage());
+ }
+ sortedAttributes.put(attributes[i].getName(), attribute);
+ }
+ Iterator keys = sortedAttributes.keySet().iterator();
+ while (keys.hasNext())
+ {
+ root.appendChild((Element)sortedAttributes.get(keys.next()));
+ }
+ }
+ }
+ if (HttpUtil.booleanVariableValue(in, "constructors", true))
+ {
+ MBeanConstructorInfo[] constructors = info.getConstructors();
+ if (constructors != null)
+ {
+ // How to order contructors?
+ for (int i=0;i<constructors.length;i++)
+ {
+ Element constructor = document.createElement("Constructor");
+ constructor.setAttribute("name", constructors[i].getName());
+ constructor.setAttribute("description", constructors[i].getDescription());
+ addParameters(constructor, document, constructors[i].getSignature());
+ root.appendChild(constructor);
+ }
+ }
+ }
+ if (HttpUtil.booleanVariableValue(in, "operations", true))
+ {
+ MBeanOperationInfo[] operations = info.getOperations();
+ if (operations != null)
+ {
+ for (int i=0;i<operations.length;i++)
+ {
+ Element operation = document.createElement("Operation");
+ operation.setAttribute("name", operations[i].getName());
+ operation.setAttribute("description", operations[i].getDescription());
+ operation.setAttribute("return", operations[i].getReturnType());
+ switch (operations[i].getImpact())
+ {
+ case MBeanOperationInfo.UNKNOWN:
+ operation.setAttribute("impact", "unknown");
+ break;
+ case MBeanOperationInfo.ACTION:
+ operation.setAttribute("impact", "action");
+ break;
+ case MBeanOperationInfo.INFO:
+ operation.setAttribute("impact", "info");
+ break;
+ case MBeanOperationInfo.ACTION_INFO:
+ operation.setAttribute("impact", "action_info");
+ break;
+ }
+ addParameters(operation, document, operations[i].getSignature());
+ root.appendChild(operation);
+ }
+ }
+ }
+ if (HttpUtil.booleanVariableValue(in, "notifications", true))
+ {
+ MBeanNotificationInfo[] notifications = info.getNotifications();
+ if (notifications != null)
+ {
+ for (int i=0;i<notifications.length;i++)
+ {
+ Element notification = document.createElement("Notification");
+ notification.setAttribute("name", notifications[i].getName());
+ notification.setAttribute("description", notifications[i].getDescription());
+ String[] types = notifications[i].getNotifTypes();
+ for (int j=0;j<types.length;j++)
+ {
+ Element type = document.createElement("Type");
+ type.setAttribute("name", types[j]);
+ notification.appendChild(type);
+ }
+ root.appendChild(notification);
+ }
+ }
+ }
+ return root;
+ }
+
+ protected void addParameters(Element node, Document document, MBeanParameterInfo[] parameters)
+ {
+ for (int j=0;j<parameters.length;j++)
+ {
+ Element parameter = document.createElement("Parameter");
+ parameter.setAttribute("name", parameters[j].getName());
+ parameter.setAttribute("description", parameters[j].getDescription());
+ parameter.setAttribute("type", parameters[j].getType());
+ parameter.setAttribute("strinit", String.valueOf(CommandProcessorUtil.canCreateParameterValue(parameters[j].getType())));
+ // add id since order is relevant
+ parameter.setAttribute("id", ""+j);
+ node.appendChild(parameter);
+ }
+ }
+
+}