| /* |
| * 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.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; |
| |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.ServerCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.ServerByDomainCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.MBeanCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.SetAttributesCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.DeleteMBeanCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.InvokeOperationCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.CreateMBeanCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.ConstructorsCommandProcessor; |
| import org.apache.felix.mosgi.jmx.httpconnector.mx4j.tools.adaptor.http.EmptyCommandProcessor; |
| |
| /** |
| * 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", ServerCommandProcessor.class.getName()}, |
| {"serverbydomain", ServerByDomainCommandProcessor.class.getName()}, |
| {"mbean", MBeanCommandProcessor.class.getName()}, |
| {"setattributes", SetAttributesCommandProcessor.class.getName()}, |
| {"setattribute", SetAttributeCommandProcessor.class.getName()}, |
| {"getattribute", GetAttributeCommandProcessor.class.getName()}, |
| {"delete", DeleteMBeanCommandProcessor.class.getName()}, |
| {"invoke", InvokeOperationCommandProcessor.class.getName()}, |
| {"create", CreateMBeanCommandProcessor.class.getName()}, |
| {"constructors", ConstructorsCommandProcessor.class.getName()}, |
| {"empty", EmptyCommandProcessor.class.getName()}}; |
| |
| // {"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, ProcessorMBean.class.getName())) |
| { |
| server.invoke(processorName, |
| "writeResponse", |
| new Object[]{out, in, document}, |
| new String[]{HttpOutputStream.class.getName(), HttpInputStream.class.getName(), Document.class.getName()}); |
| 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, ProcessorMBean.class.getName())) |
| { |
| server.invoke(processorName, |
| "notFoundElement", |
| new Object[]{path, out, in}, |
| new String[]{String.class.getName(), HttpOutputStream.class.getName(), HttpInputStream.class.getName()}); |
| 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, ProcessorMBean.class.getName())) |
| { |
| HttpAdaptor.log(LogService.LOG_DEBUG,"Preprocessing",null); |
| path = (String)server.invoke(processorName, |
| "preProcess", |
| new Object[]{path}, |
| new String[]{String.class.getName()}); |
| 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, ProcessorMBean.class.getName())) |
| { |
| server.invoke(processorName, |
| "writeError", |
| new Object[]{out, in, e}, |
| new String[]{HttpOutputStream.class.getName(),HttpInputStream.class.getName(), Exception.class.getName()}); |
| 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(HttpAdaptor.class.getName()+".log: No bundleContext"); |
| } |
| } |
| } |
| |