# HttpAdaptor

## Introduction

The HttpAdaptor offers a basic way to interface with an MX4J agent. It contains a simple HTTP 1.0 server, able to translate HTTP requests to JMX requests. Obviously it has some limitations, like not being able to manipulate data which cannot be obtained from Strings. As an advantage HTTP traffic is usually enabled through firewalls and you can use your browser as a client.

The MX4J HttpAdaptor is built basically to serve XML data. Requests are made with normal http requests and they are answered by constructing a XML tree containing the requested data. The request may also have variables which may specify exactly the requested data. The XML tree can be later processed by defining a ProcessorMBean, which has the task to take the XML tree and do something with it. The processor will also be responsible to serve requests not understood by the server. In this way an appropriate processor can serve images and raw html. Currently there are two Processors defined:

- DefaultProcessorMBean: It does not modify the XML tree limiting itself to publish the tree as text. Defining the content-type as text/xml. This usually means that your browser will display the XML text. This processor won't server any data besides the XML files.

- XSLTProcessorMBean: This processor takes the XML tree and transforms it to HTML by means of XSLT. This requires that you use some JAXP-compliant XSLT. It has been tested mainly with Xalan XSLT processor. The processor is also able to serve images and other files.

As the processor is an MBean it means you can deploy and modify it on runtime. The HttpAdaptorMBean defines three methods to set the Processor. If no processor is defined or an error is found, the DefaultProcessor will be used.

## Parameters and operations

The HttpAdaptor is an MBean defined by the interface HttpAdaptorMBean. It contains the following parameters.

- Port: Defines the port in which the server will be listening to. By default is 8080.

- Host: Defines the host name in which the server will be listening to. By default is localhost. This means that you can't access the server from another computer. This is good for security reasons, forcing you to explicitly open the server to the outside. You can also use 0.0.0.0 which will open the server to all local interfaces

- Alive: Boolean property which tells whether the server is running or not.

- AuthenticationMethod: Sets the authentication method. Valid values are none, basic, digest. Please refer to the security chapter

- Processor: This sets the processor object to be used after the XML tree construction. If used the ProcessorName is set to null.

- ProcessorName: This sets the MBean's ObjectName to be used as XML processor. If used then Processor is set to null. The MBean has to implement the `mx4j.tools.adaptor.http.ProcessorMBean` interface

- ProcessorNameString: The same as before but the object name is passed as a string

- ProcessorClass: This will take a class name as string and instantiate a class object. The class has to implement the `mx4j.tools.adaptor.http.ProcessorMBean` interface, and you have to set the ProcessorName or ProcessorNameString property

- SocketFactory: Replaces the default socket factory with another, for example, the mx4j.tools.adaptor.http.ssl.SSLFactory

- SocketFactoryName: Replaces the default socket factory with another using an ObjectName, the pointed mbean has to have an public ServerSocket createServerSocket(int port, int backlog, String host) throws IOException method

- SocketFactoryNameString: Same as previous but it takes a String object

- StartDate: Date and Time when the Adaptor was started

- RequestsCount: Total amount of requests served

- Version: HttpAdaptor's version

The HttpAdaptor accept the following operations

- start(): Starts the HttpAdaptor, notice that the server does not start by itself

- stop(): Stops the server

- addCommandProcessor(String path,HttpCommandProcessor processor): It adds a command processor and assigns it to the path. You can use this to create your own command processors which generate a customized XML tree. Notice that if the path was assigned before this command will replace the previous definition

- addCommandProcessor(String path,String classname): Same as previous but the processor object is indicated with a classname, the operation will try to instantiate an object of the given class, check that implements the `mx4j.tools.adaptor.http.HttpCommandProcessor` interface, and assign it to the indicated path

- void removeCommandProcessor(String path): Removes a command processor assigned to the give path

## Security

The HttpAdaptor is in no way guaranteed to be secure. However basic authentication and SSL support are available.

### Basic Authentication

The Basic Authentication method provides a weak form of protection. When it is set your browser should prompt you for a username and password which are compared with the ones stored in the Adaptor. To add a username/password pair use the addAuthorization method. As mentioned before the basic authentication is weak since your username and password are sent with a weak encoding (Base64). However it can be prefectly used in secured networks or via enabling SSL.

### SSL support

The HttpAdaptor can use SSL instead of normal sockets. For that is necessary three steps:

- Install JSSE:

  JSSE is necessary to run the Adaptor with SSL support. It is possible to use either JSSE version 1.0.2 available here, or JDK 1.4. JSSE comes with 3 jar files which should be added to your classpath: jsse.jar, jcert.jar and jnet.jar. Another alternative is to put those files at your JAVA_HOME/lib/ext dir. In case you are using JDK 1.4 you don't need to do this

- Create server certificate:

  Use the keytool command to create a server certificate. For example

  keytool -genkey -keystore certs -keyalg RSA

  where certs is the keystore file name. You will be prompted for a password for the keystore and the certificate distinguished name. Notice that your browser will probably complain about the vailidty of the key since it was signed by yourself.

  Note that if the key generation algorithm is not RSA but something else your browser may not accept it

- Configure HttpAdaptor:

  Finally you should change the default socket factory for a SSL factory. To do that you should use the SocketFactory attribute passing a `mx4j.tools.adaptor.http.ssl.SSLFactory` object. The SSLFactory object should be previoulsy configured with your keystore and key.

After this you can start the HttpAdaptor as usual and point to https://host:port instead of http://host:port

### SSLFactory

The SSLFactory contains several parameters you need to configure to find the certificate keystore. They are in the SSLFactory Management interface

- KeyStoreType: Sets the keystore type. If you used the keytool command this is JKS
- KeyStoreFileName: Filename of the certificate file
- KeyStorePassword: Keystore password
- KeyManagerAlgorithm: Keymanagers's algorithm, by default is SunX509
- KeyManagerPassword: Keymanagers's password
- SSLProtocol: SSL's protocol, by default is SSLv3

## Usage

To use the HttpAdaptor you should instantatiate the MBean and register it to the right server. Later you can set up the desired parameters and invoke start to init the operation. Remember to add a JAXP-compliant parser such as xerces to the CLASSPATH. If you want to use the XSLTAdaptor you should also add xalan.jar to the CLASSPATH. If you want to use SSL add the JSSE jar files

### Instantiating the HttpAdaptor

    import mx4j.tools.adaptor.http.HttpAdaptor;

    MBeanServer server = ...;
    HttpAdaptor adapter = new HttpAdaptor();
    ObjectName name = new ObjectName("Server:name=HttpAdaptor");
    server.registerMBean(adapter, name);
    adapter.setPort(XXX);
    adapter.setHost("XXX");
    adapter.start();

    or...
    server.createMBean("mx4j.tools.adaptor.http.HttpAdaptor", name, null);
    server.setAttribute(name, new Attribute("Port", new Integer(XXX)));
    server.setAttribute(name, new Attribute("Host", "XXX"));
    server.invoke(name, "start", null, null);

If you wan to use a non-default Processor. You may instantiate and install it as follow

### Installing a non-default Processor

    MBeanServer server = ...;
    ObjectName name = new ObjectName("Server:name=HttpAdaptor");
    ObjectName processorName = new ObjectName("Server:name=XSLTProcessor");
    server.createMBean("mx4j.tools.adaptor.http.HttpAdaptor", name, null);
    server.createMBean("mx4j.tools.adaptor.http.XSLTProcessor", processorName, null);
    server.setAttribute(name, new Attribute("ProcessorName", processorName));

## Available requests

The HttpAdaptor works by interpreting requests and executing some action. The Adaptor has a list of available requests and they produce an XML ouput tree (Or an exception...). New request handlers can be added if necessary, creating a `mx4j.tools.adaptor.http.HttpCommandProcessor` implementation, and add it to the HttpAdaptor using the addCommandProcessor and removeCommandProcessor.

The following is a list of the currently available requests, and the results and parameters required.

- http://host:port/serverbydomain Returns a list of the MBeans available in the server grouped by domain. The result tree is as follows:

      <Server>
      	<Domain name="Http">
      		<MBean classname="mx4j.tools.adaptor.http.HttpAdaptor" description="HttpAdaptor MBean" objectname="Http:name=HttpAdaptor"></MBean>
      		<MBean classname="mx4j.tools.adaptor.http.XSLTProcessor" description="XSLT Processor" objectname="Http:name=XSLTProcessor"></MBean>
      	</Domain>
      	<Domain name="JMImplementation">
      		<MBean classname="javax.management.MBeanServerDelegate" description="" objectname="JMImplementation:type=MBeanServerDelegate"></MBean>
      	</Domain><Domain name="Test">
      </Server>

  The request can accept the following parameters:

  - instanceof: Filters the MBeans whether they are instance of the class. For instance http://host:port/serverbydomain?instanceof=javax.management.timer.Timer will produce a list of all timers
  - querynames: Filters the MBeans by objectname for instance http://host:port/serverbydomain?querynames=*:* will produce a list of all mbeans whether http://host:port/serverbydomain?querynames=Test:* will only contain those MBeans in the Test domain

- http://host:port/server Returns a list of the MBeans available in the server. The result tree is as follows:

      <Server>
      	<MBean objectname="Http:name=HttpAdaptor"></MBean>
      	<MBean objectname="Http:name=XSLTProcessor"></MBean>
      	<MBean objectname="JMImplementation:type=MBeanServerDelegate"></MBean>
      </Server>

  The request can accept the following parameters:

  - instanceof: Filters the MBeans whether they are instance of the class. For instance http://host:port/serverbydomain?instanceof=javax.management.timer.Timer will produce a list of all timers

- http://host:port/mbean?objectname=XXX Returns the description of the referred MBean. It requires that the target objectname is passed on the request. The result tree for the request is as follows http://host:port/mbean?objectname=Test:name=test1

      <MBean classname="test.mx4j.tools.adaptor.http.HttpAdaptorXMLTest$TestClass" description="" objectname="Test:name=test1">
      	<Attribute availability="RO" description="" isnull="false" name="Double" type="java.lang.Double" value="0.0"/>
      	<Attribute availability="RW" description="" isnull="false" name="Str" type="java.lang.String" value="t1"/>
      	<Attribute availability="RO" description="" isnull="false" name="True" type="boolean"  value="true"/>
      	<Constructor description="" name="test.mx4j.tools.adaptor.http.HttpAdaptorXMLTest$TestClass">
      		<Parameter description="" id="0" name="" type="java.lang.String"/>
      	</Constructor>
      	<Operation description="" impact="unknown" name="aMethod" return="java.lang.Boolean">
      		<Parameter description="" id="0" name="" type="java.lang.String">
      		</Parameter>
      	</Operation>
      	<Operation description="" impact="unknown" name="anotherMethod" return="void">
      		<Parameter description="" id="0" name="" type="java.lang.String"></Parameter>
      		<Parameter description="" id="1" name="" type="int"></Parameter>
      	</Operation>
      	<Notification description="test" name="name">
      		<Type name="test1"></Type>
      		<Type name="test2"></Type>
      		</Notification>
      </MBean>

  The Attribute element may have an aggregation attribute for composite types array, collection and map

  The request can accept the following extra parameters:

  - attributes: if set to false as http://host:port/mbean?objectname=Test:name=test1&attributes=false no attributes are included in the result tree
  - operations: if set to false as http://host:port/mbean?objectname=Test:name=test1&operations=false no operations are included in the result tree
  - constructors: if set to false as http://host:port/mbean?objectname=Test:name=test1&constructors=false no constructors are included in the result tree
  - notifications: if set to false as http://host:port/mbean?objectname=Test:name=test1&notifications=false no notifications are included in the result tree

- http://host:port/getattribute?objectname=XXX&attribute=XXX&format=ZZZ Gets the value of an attribute. This is an operation intended to get certain types of attributes in a usable format, in particular arrays. If format is omited or not understood the default value is returned like:

      <MBean objectname="Test:name=test1">
      	<Attribute classname="java.lang.String" isnull="false" name="Str" value="t1"/>" +
      </MBean>"

  However if format=array and the attribute is actually an array the result is like

      <MBean objectname="Test:name=test3">
      	<Attribute classname="[Ljava.lang.String;" isnull="false" name="StrArray">
      		<Array componentclass="java.lang.String" length="3">
      			<Element element="a" isnull="false" index="0"/>
      			<Element element="b" isnull="false" index="1"/>
      			<Element element="c" isnull="false" index="2"/>
      		</Array>
      	</Attribute>
      </MBean>

  If format=collection and the attribute is a collection the result is like

      <MBean objectname="Test:name=test3">
      	<Attribute classname="java.util.List" isnull="false" name="List">
      		<Collection length="3">
      			<Element elementclass="java.lang.String" element="a" index="0"/>
      			<Element elementclass="java.lang.String" element="b" index="1"/>
      			<Element elementclass="java.lang.String" element="c" index="2"/>
      		</Collection>
      	</Attribute>
      </MBean>

  If format=map and the attribute is a map the result is like

      <MBean objectname="Test:name=test3">
      	<Attribute classname="java.util.Map" isnull="false" name="Map">
      		<Map length="3">
      			<Element elementclass="java.lang.String" element="a" keyclass="java.lang.Integer" key="0"/>
      			<Element elementclass="java.lang.String" element="b" keyclass="java.lang.Integer" key="1"/>
      			<Element elementclass="java.lang.String" element="c" keyclass="java.lang.Integer" key="2"/>
      		</Map>
      	</Attribute>
      </MBean>

  The request requires the following parameters:

  - objectname: Target objectname
  - attribute: Attribute's name
  - format: Result format. The currently supported types are array, collection and map

- http://host:port/setattribute?objectname=XXX&attribute=XXX&value=XXX Sets the value of one attribute. This is an operation request rather that a data request. All operation requests are returned as a MBeanOperation tree, which looks as follow

      <MBeanOperation>
      	<Operation objectname="Test:name=test1" operation="setattribute" result="success"/>
      </MBeanOperation>

  or if there was an error it looks like

      <MBeanOperation>
      	<Operation errorMsg="Attribute Number not found" objectname="Test:name=test1" operation="setattribute" result="error"/>
      </MBeanOperation>

  The request requires the following parameters:

  - objectname: Target objectname
  - attribute: Attribute's name
  - value: Attribute's value

  setattribute is deprecated in 1.1.1 and setattributes should be used instead

- http://host:port/setattributes?objectname=XXX&value_YYY=XXX&value_YYY2=XXX2&[set_XXX=Set | setall] Sets the value of many attributes. This is an operation request. The result will be a list of the attributes set.

      <MBeanOperation>
      	<Operation objectname="Test:name=test1" operation="setattribute">
      		<Attribute attribute="YYY" value="XXX" result="success"/>
      		<Attribute attribute="YYY2" value="XXX2" result="success"/>
      	</Operation>
      </MBeanOperation>

  or if there was an error it looks like

      <MBeanOperation>
      	<Operation objectname="Test:name=test1" operation="setattribute">
      		<Attribute attribute="YYY" errorMsg="Some error message" result="error"/>
      		<Attribute attribute="YYY2" value="XXX2" result="success"/>
      	</Operation>
      </MBeanOperation>

  The request requires the following parameters:

  - objectname: Target objectname
  - value_XXX: Value for the atribute name XXX. The request can pass many parameters, but it depends on the set_XXX parameters which values will be set
  - [set_XXX=Set | setall]: Indicates which value is used. If setall is present it will set all attributes passed. If only set_XXX is passed that will be set.

  Notice that in case of one attribute failing the other will be set anyway

- http://host:port/invoke?objectname=XXX&operation=XXX&type0=XXX&value0=XXX... Invokes an operation on the target MBean

      <MBeanOperation>
      	<Operation objectname="Test:name=test1" operation="invoke" result="success" return="true"/>
      </MBeanOperation>

  The following parameters are required:

  - objectname: Target objectname
  - operation: Name of the operation

  If you want to invoke an operation which takes parameters, add the following parameters:

  - typeX: Type of the parameter number X. They are enumerated starting from 0
  - valueX: Value of the parameter number X. They are enumerated starting from 0

- http://host:port/delete?objectname=XXX Removed the target MBean

      <MBeanOperation>
      	<Operation objectname="Test:name=test1" operation="delete" result="success"/>
      </MBeanOperation>

  The following parameter is required:

  - objectname: Target objectname

- http://host:port/create?class=XXX&objectname=XXX&type0=XXX&value0=XXX... Creates a target MBean invoking the corresponding constructor

      <MBeanOperation>
      	<Operation objectname="Test:name=test1" operation="invoke" result="success" return="true"/>
      </MBeanOperation>

  The following parameters are required:

  - classname: Target objectname
  - objectname: Target objectname

  If you want to invoke create using a constructor which takes parameters, add the following parameters:

  - typeX: Type of the parameter number X. They are enumerated starting from 0
  - valueX: Value of the parameter number X. They are enumerated starting from 0

- http://host:port/constructors?classname=mx4j.tools.adaptor.http.HttpAdaptor Queries the MBean server of the available constructors for a class name resulting on

      <Class classname="mx4j.tools.adaptor.http.HttpAdaptor">
      	<Constructor name="mx4j.tools.adaptor.http.HttpAdaptor">
      		<Parameters ...>
      		</Parameters>
      	</Constructor>
      </Class>

  The following parameter is required:

  - classname: Target classname

  In case the class is not found an exception will be sent as

      	<Exception classname="mx4j.tools.adaptor.http.HttpAdaptor" errorMsg="class XXX not found"/>

- http://host:port/empty The empty request returns an empty xmltree. Is basically used to create 'static' requests made on pure xsl. The result tree is as

      <empty/>