AMT and Java (JAX-WS method)

AMT, SOAP and WSDL

AMT is a management technology from Intel. You can control AMT via SOAP messages over the network and the SOAP messages structure is defined in WSDL files (see the WSDL file attached).

When you develop a software interacting with SOAP web services, you typically don't write XML yourself. It's more interesting to give the WSDL descriptor to a web service stack and let him do the interface between an object oriented method calls and XML messages. Less coding, more automation thanks to descriptors.

You may want to check the previous article on SOAP and WSDL for AMT.

Java

If you want to work with WSDL in Java, in the past you could have used AXIS from the Apache project. But nowadays it's probably a good idea to use Java API for XML Web Services "JSR 224" (a JSR is a standard in the java world). JAX-WS is the reference implementation for JSR 224 (jax-ws.dev.java.net).

If you work with the Sun JVM, it's included in recent versions. In this post I'll work with the Sun JDK 1.6.0.14. In the past all the SOAP stuff was in the Java Enterprise development kit, but now it's standardized and included in the client JVM/SDK.

Remember that in our case the server side is in fact the AMT aware laptop or desktop itself, on the hardware level. All we need to do is create a SOAP client.

Logistics

You don't have to run the sample codes to read this post, but I've created a few simple codes to let you experiment.
The main code is attached to this post or available with syntax coloring from the SVN browser, and the complete environment is available on javaintelamt.sf.net in case you use SVN :

svn co https://javaintelamt.svn.sourceforge.net/svnroot/javaintelamt javaintelamt

Or as a simple zip file if you don't : javaintelamt_softwareblogs_1.0.zip

Note : you'll find more codes on the javaintelamt.sf.net SVN server in the future as it's an evolving project.
So please download the zip, unzip it and read the (short) REAME.txt. You need "ant" and "java" in your path (I am using version 1.6). Ant is like make in the java world, it helps a LOT.

WSDL to Java

So we have a WSDL file, but we want to code with java objects. To generate automatically the .java (and .class) files we have a tool called wsimport in the Java SDK. You could run it as a stand alone command line tool, but it's easier to use it from ant. There's an ant task for it in the webservices jars, we just need to use a taskdef to be able to use it :

<target name="wsimport">

<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
<classpath refid="classpath" />
</taskdef>

<wsimport debug="true" verbose="true" keep="true"
destdir="tmp/gen" package="${wsimport.package}.remotecontrol"
wsdl="WSDL/RemoteControlInterface.wsdl" />

</target>

If you launch "ant wsimport" you should see 2 steps : first the generation of .java files, then the compilation. Everything will be available from a java top package, in my case "eu.guermonprez.paul.oss.iamt.wsimport.remotecontrol".
You can look at the generated files in "tmp/gen/eu/guermonprez/paul/oss/iamt/wsimport/remotecontrol/"

Hello AMT World : Basics

Let's create a simple software to reboot a remote machine :
"src/eu/guermonprez/paul/oss/iamt/HelloAMT.java" (also attached to this post and available with syntax coloring).

If you look at the headers, I had to import a "Service" and a "SoapPortType" from the generated files.

SOAP messages are sent via a simple socket, but protected with a "digest" Authentication (just like a regular password protected website). So i defined the default Authenticator with my login/password :

Authenticator.setDefault(new DigestAuthenticator(login, password));

Hello AMT World : Service and Port

We need to instantiate a service first. The service main utility will be to create a SOAP port.

RemoteControlService service = new RemoteControlService();
RemoteControlSoapPortType rcPort =
(RemoteControlSoapPortType) service.getRemoteControlSoapPort();

The term SOAP port may be misleading, as it's not a port as in "port 80 for web service". A SOAP port is a definition of a web service instance.

With "getRemoteControlSoapPort" we had a definition but no parameters, nothing was sent over the network.
We need to provide the hostname and port number for the rcPort. Why such a strange line to define something that important you may wonder ? Well the typical deployment model of web services is to configure the server name in a XML file or via an enterprise directory. The server is usually the place where you got your preconfigured client application from, over the network.
In AMT it's different, each AMT machine is a web server receiving SOAP messages, so we have to define the server hostname at runtime. Possible of course but not very nice. Port by default is 16992.

((BindingProvider) rcPort).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://" + host + ":" + port + "/RemoteControlService");

You rcPort is now fully configured and ready to launch remote calls over SOAP.

Hello AMT World : Holders ?

We are executing remote procedure calls ("RPC") over SOAP. It may look like a regular method calls, but it's a communication between a Java JVM and a remote web server, not even in Java. So you can't work with objects like a Long in memory. You need to use Holders to carry the value of an object instead.
The procedure is : I know I'll receive a Long for the system power state from my RPC, so I am creating an empty Holder systemPowerState, I give it as as argument to my RPC and the result will be stored in this Holder after the call. You'll access the value with "systemPowerState.value", but it's your job to remember it's a Long and ask for "systemPowerState.value.longValue()".

If you need to give an argument to a RPC expecting nothing in return, a regular variable is enough. That would be the case for "rcPort.remoteControl".

Now you should be able to understand :

Holder<Long> status = new Holder<Long>();
Holder<Long> systemPowerState = new Holder<Long>();

rcPort.getSystemPowerState(status, systemPowerState);

long statusLong = status.value.longValue();
long systemPowerStateLong = systemPowerState.value.longValue();

Hello AMT World : Values ?

System power state 0 means system running, 5 not running. The codes are documented in the SDK documentation or the WSDL itself.
Technical note : If you know how to access the WSDL annotations from Java (I don't), please contact me : paul.guermonprez@intel.com

The status is a return code. 0 is fine, you may see return codes for unsupported methods or unsupported argument.

Run

Make sure you have java and ant in your path, customize the "build.properties" file (see README.txt) and run : "ant wsimport", then "ant run" to compile and launch the "HelloAMT" simple software.
You should see something like :

[java] HelloAMT : Simple software to display the status of Intel AMT aware computers
[java] 
[java] Copyright 2009 Paul Guermonprez paul@guermonprez.eu
[java] GNU Lesser General Public License
[java] 
[java] status : 0
[java] power : 0
[java] host : charcot
[java] login : admin
[java] password : titiTOTO1!
[java] SOAP : JAX-WS RI 2.1.3.1-hudson-749-SNAPSHOT: Stub for http://charcot:16992/RemoteControlService

If you run "ant test", the software launched will be "Test" on the same machine. Test is REBOOTING the AMT machine !

A little further

It's not that complicated don't you think ? But I don't like to work with BindingProvider and Holders, so I created a simple wrapper called "RemoteControl".

The code is even simpler and shorter :

Authenticator.setDefault(new DigestAuthenticator(login, password));

RemoteControl rc = new RemoteControl(host);
rc.bind();
System.out.println("reboot return code = " + rc.resetPowerCycle());

Hope you liked it. More Java codes in the next episode !
For more complete information about compiler optimizations, see our Optimization Notice.
AttachmentSize
File helloamt.java3.67 KB

7 comments

Top
tgreben's picture

Hi Bill,

Here is the way how to make jax-ws to put "encoding" into xml header.

1. Create a decorator of XMLStreamWriter that enforces "encoding" to be put into xml header:

[code=java]
public class StreamWriter implements XMLStreamWriter {
private final XMLStreamWriter impl;
public StreamWriter(XMLStreamWriter impl) {
this.impl = impl;
}
public void writeStartDocument() throws XMLStreamException {
writeStartDocument("1.0");
}
public void writeStartDocument(String encoding, String version)
throws XMLStreamException {
impl.writeStartDocument(encoding, version);
}
public void writeStartDocument(String version)
throws XMLStreamException {
writeStartDocument("UTF-8", version);
}
//... (other XMLStreamWriter methods delegating to impl)
}
[/code]

2. Create a decorator of XMLOutputFactory that returns decorated XMLStreamWriter where needed:

[code=java]
public class XMLOutputFactoryWithEncoding extends XMLOutputFactory {
private final XMLOutputFactory impl;
public XMLOutputFactoryWithEncoding(XMLOutputFactory impl) {
this.impl = (impl == null) ? XMLOutputFactory.newInstance() : impl;
}
public XMLStreamWriter createXMLStreamWriter(OutputStream stream,
String encoding) throws XMLStreamException {
return new StreamWriter(impl.createXMLStreamWriter(stream, encoding));
}
public XMLStreamWriter createXMLStreamWriter(OutputStream stream)
throws XMLStreamException {
return new StreamWriter(impl.createXMLStreamWriter(stream));
}
public XMLStreamWriter createXMLStreamWriter(Result result)
throws XMLStreamException {
return new StreamWriter(impl.createXMLStreamWriter(result));
}
public XMLStreamWriter createXMLStreamWriter(Writer stream)
throws XMLStreamException {
return new StreamWriter(impl.createXMLStreamWriter(stream));
}
//... (other XMLOutputFactory methods delegating to impl)
}
[/code]

3. Create utility class for modifying default XMLStreamWriterFactory:

[code=java]
public class XMLStreamWriterFactoryModifier {
private static XMLStreamWriterFactory oldFactory = null;

private XMLStreamWriterFactoryModifier() {
}

/**
* @return <code>true</code> if factory was modified, otherwise <code>false</code>
*/
public static synchronized boolean modify() {
if(oldFactory != null) return false;

// Code below corresponds to static section of XMLStreamWriterFactory
XMLOutputFactory xof = null;
if (Boolean.getBoolean(XMLStreamWriterFactory.class.getName()+".woodstox")) {
try {
xof = (XMLOutputFactory)Class.forName("com.ctc.wstx.stax.WstxOutputFactory").newInstance();
} catch (Exception e) {
// Ignore and fallback to default XMLOutputFactory
}
}
if (xof == null) {
xof = XMLOutputFactory.newInstance();
}

xof = new XMLOutputFactoryWithEncoding(xof);

XMLStreamWriterFactory f=null;

// this system property can be used to disable the pooling altogether,
// in case someone hits an issue with pooling in the production system.
if(!Boolean.getBoolean(XMLStreamWriterFactory.class.getName()+".noPool")) {
f = XMLStreamWriterFactory.Zephyr.newInstance(xof);
}
if(f==null) {
// is this Woodstox?
if(xof.getClass().getName().equals("com.ctc.wstx.stax.WstxOutputFactory")) {
f = new XMLStreamWriterFactory.NoLock(xof);
}
}
if (f == null) {
f = new XMLStreamWriterFactory.Default(xof);
}

oldFactory = XMLStreamWriterFactory.get();
XMLStreamWriterFactory.set(f);
Logger.getLogger(XMLStreamWriterFactory.class.getName()).fine("XMLStreamWriterFactory instance is = "+f);

return true;
}

/**
* @return <code>true</code> if factory was restored to its previous state, otherwise <code>false</code>
*/
public static synchronized boolean rollback() {
if(oldFactory == null) return false;
XMLStreamWriterFactory.set(oldFactory);
Logger.getLogger(XMLStreamWriterFactory.class.getName()).fine("XMLStreamWriterFactory instance is = "+oldFactory);
return true;
}
}
[/code]

4. Put the following line somewhere were application is initialized (e.g. as a first line in main() ):
[code=java]
XMLStreamWriterFactoryModifier.modify();
[/code]

Solution is tested and works on my environment. SOAP requests contain header with [code]encoding="utf-8"[/code] and that makes AMT happy. :-)
I don't have an option to attach source code here, so it is available upon request.

Best regards,
Taras.

anonymous's picture

am using axis to get java file from wsdl its working for all the wsdl files in the (Intel amt sdk doc/wsdl)
except the Remote accessAdmininterface.wsdl if i try to get the java file it give only four files

Any help is needed

thanks in Advanced

anonymous's picture

Hi Paul,
Thanks for the insight in to Java code for Intel AMT. I am trying to get use HardwareAssetInterface to get hardware asset information. Below is what I am trying to (similar to the HelloAMT code provided by you).

HardwareAssetService hardwareAssetService = new HardwareAssetService();
HardwareAssetSoapPortType hwAssetSoapPortType =
(HardwareAssetSoapPortType) hardwareAssetService.getHardwareAssetSoapPort();
((BindingProvider) hwAssetSoapPortType).getRequestContext(). put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http: // 192.168.0.123:16992/HardwareAssetInterface");
Holder<Long> status = new Holder<Long>();
Holder<Long> count = new Holder<Long>();
Holder<AssetDataArrayType> assetData = new Holder<AssetDataArrayType>();
Long assetType = new Long(1);
hwAssetSoapPortType.getAssetData(assetType, status, count, assetData);

But I get the below exception in getAssetData() method:
com.sun.xml.ws.client.ClientTransportException: HTTP Status-Code 404: Not Found - Not Found
at com.sun.xml.ws.transport.http.client.HttpClientTransport.checkResponseCode(HttpClientTransport.java:219)

I am using Intel Management Engine 5.1.0 Version.
Could please anyone help on the same?

Thanks in anticipation.
Warm regards,
Hemant Malik

anonymous's picture

Hello bill,

The problem is coming from the encoding specification in the XML header (not the HTTP header).
some AMT machines (recent firmware) need the utf-8 encoding specification in the XML header.

(the encoding specification i nthe XML header is useless and not mandatory i nSOAP, but needed for some AMT machines ...)

regards, paul

anonymous's picture

P.S. Saw your forum post on this same issue. Any update from the engineers?

anonymous's picture

Paul:
I'm having a problem with AMT and JAX-WS that doesn't appear to be a problem in Axis. I'd prefer to use JAX-WS, since its footprint is smaller, but both your code and mine fail with the same problem.

I'm talking to an AMT 5.0.3 machine (Dell Optiplex 960). An exception is thrown:

javax.xml.ws.soap.SOAPFaultException: Failed to parse the request

(I had to add a SOAP fault handler to get around another JAX-WS problem where the default exception handler assumes that the fault namespace is not null).

This is with the latest JDK (1.6 update 12 and 13).

As I said, this works fine with Axis1, but for some reason, AMT doesn't seem to like the request sent by JAX-WS.

Thoughts?

Thanks...

Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.