So I'm running out of ideas to try to actually get a client to connect to the SOAP service I'm running through axis2.
I tried two methods, one was to use wsdl2java to build the stub and associated client side classes, and then write a Client class that build the requests messages and sends them through the Stub. The other way was to use the ServiceClient to connect..
Both are failing in their own way..
Option #1, every time a message is sent through the stub I get this back:
org.apache.axis2.AxisFault: The input stream for an incoming message is null.
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:87)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:67)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:354)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:417)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
Option #2, everytime I run it I get this Exception:
org.apache.axis2.deployment.DeploymentException: org.apache.axis2.transport.local.LocalTransportSender
Option #2 source:
import javax.xml.stream.XMLStreamException;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.Constants;
import org.apache.axis2.client.ServiceClient;
public class loyaltyClient {
private static EndpointReference targetEPR =
new EndpointReference(
"http://localhost:8080/axis2/services/service");
public static OMElement verifyCustomer(String customer_id) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
"http://localhost/", "service");
OMElement method = fac.createOMElement("VerifyCustomer", omNs);
OMElement value1 = fac.createOMElement("customer_id",omNs);
OMElement value2 = fac.createOMElement("source_id",omNs);
OMElement value3 = fac.createOMElement("source_password",omNs);
OMElement value4 = fac.createOMElement("source_txnid",omNs);
OMElement value5 = fac.createOMElement("timestamp",omNs);
value1.addChild(fac.createOMText(value1, customer_id));
value2.addChild(fac.createOMText(value2, "source"));
value3.addChild(fac.createOMText(value3, "1234"));
value4.addChild(fac.createOMText(value4, "123"));
value5.addChild(fac.createOMText(value5, "06-01-2010 12:01:01"));
method.addChild(value1);
method.addChild(value2);
method.addChild(value3);
method.addChild(value4);
method.addChild(value5);
return method;
}
public static void main(String[] args) {
try {
OMElement vctest = loyaltyClient.verifyCustomer("6177740603");
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
OMElement result = sender.sendReceive(vctest);
String response = result.getFirstElement().getText();
System.out.println(response);
} catch (Exception e) { //(XMLStreamException e) {
System.out.println(e.toString());
}
}
}
I've also encountered the error "The input stream for an incoming message is null" while using Axis to connect to a .Net service provider.
The problem is that .Net doesn't not support a feature called "chunked encoding", by default Axis will break its request header in chunks which is suppose to be a HTTP 1.1 compliant thing.
Anyway, you can turn this feature off in Axis by doing the following:
// Turn off the Axsis Chunked feature, some service providers (like .Net) don't support chunked headers.
Options options = serviceClient.getOptions();
options.setProperty(HTTPConstants.CHUNKED, Constants.VALUE_FALSE);
serviceClient.setOptions(options);
This worked for me. Another thing to make sure of when dealing with .Net services is to be able to specify the port name and make sure your message payload has the namespace prefix for each element.
Hope this info helps somebody.
Cheers,
DC
With the caveat that Axis2 is a buggy pile of crap, I recently had to write an Axis2 client, and found that using the default ServiceClient() constructor didn't work well -- I had to manually create a ConfigurationContext, etc. I found that using ServiceClient.getOptions() instead of creating new Options() preserved some default data. I'd also recommend dropping the options.setTransportInProtocol(...) unless you really need it -- everything should work fine via HTTP without this. Also, you may need to set options.setAction(...) to correspond with the "operation" in your WSDL.
I've included the bulk of my client (with sensitive information stripped out), in hopes that it will help. You can probably safely ignore the portions regarding addressing unless you plan to use WS-Addressing.
ConfigurationContext cfgCtx = null;
try {
/* Passing null to both params causes an AxisConfiguration to be created that uses
* the default axis2.xml file, which is included in the axis2 distribution jar.
* This is ideal for our case, since we cannot pass a full file path (relative
* paths are not allowed) because we do not know where the customer will deploy
* the application. This also allows engaging modules from the classpath. */
cfgCtx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null , null);
} catch (AxisFault e) {
// Bubble up the error
}
ServiceClient svcClient = null;
try {
svcClient = new ServiceClient(cfgCtx, null);
} catch (AxisFault e) {
// Bubble up the error
}
try {
/* This will work with the above ConfigurationContext as long as the module
* (addressing-1.5.1.mar) is on the classpath, e.g. in shared/lib. */
svcClient.engageModule("addressing");
} catch (AxisFault e) {
// Bubble up the error
}
Options opts = svcClient.getOptions();
opts.setTo(new EndpointReference("http://myservername:8080/axis2/services/MyService"));
opts.setAction("urn:doSomething"); // Corresponds to the "operation" in MyService's WSDL
opts.setSoapVersionURI(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI); // Set output to SOAP 1.2
SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
svcClient.addHeader(createSOAPSecurityHeader(factory, response)); // CreateSOAPHeader just creates an OMElement
try {
svcClient.sendReceive(createSOAPBody(factory, response)); // CreateSOAPBody just creates an OMElement
} catch (AxisFault e) {
throw new ResponseDeliveryException(1, "Error sending SOAP payload.", e);
}
Related
I'm trying to set up AWS SAM locally so I don't have to deploy every time I make a code change. But I'm having trouble getting the secrets out of Secrets Manager. I've created a new SAM project using sam init --runtime java
I then created a new secret in Secret Manager, and changed the code in the HelloWorldFunction to try to retrieve the secret.
package helloworld;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.*;
/**
* Handler for requests to Lambda function.
*/
public class App implements RequestHandler<Object, Object> {
public Object handleRequest(final Object input, final Context context) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("X-Custom-Header", "application/json");
try {
String secretName = "testsecret";
String region = "us-west-2";
// Create a Secrets Manager client
AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard()
.withRegion(region)
.build();
String secret, decodedBinarySecret;
GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest()
.withSecretId(secretName);
GetSecretValueResult getSecretValueResult = null;
try {
getSecretValueResult = client.getSecretValue(getSecretValueRequest);
} catch (DecryptionFailureException e) {
// Secrets Manager can't decrypt the protected secret text using the provided KMS key.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InternalServiceErrorException e) {
// An error occurred on the server side.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InvalidParameterException e) {
// You provided an invalid value for a parameter.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (InvalidRequestException e) {
// You provided a parameter value that is not valid for the current state of the resource.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
} catch (ResourceNotFoundException e) {
System.out.println(e.getMessage());
StringWriter outError = new StringWriter();
e.printStackTrace(new PrintWriter(outError));
System.out.println(outError.toString());
// We can't find the resource that you asked for.
// Deal with the exception here, and/or rethrow at your discretion.
throw e;
}
// Decrypts secret using the associated KMS CMK.
// Depending on whether the secret is a string or binary, one of these fields will be populated.
if (getSecretValueResult.getSecretString() != null) {
secret = getSecretValueResult.getSecretString();
return new GatewayResponse(secret, headers, 200);
}
else {
decodedBinarySecret = new String(Base64.getDecoder().decode(getSecretValueResult.getSecretBinary()).array());
return new GatewayResponse(decodedBinarySecret, headers, 200);
}
} catch (Exception e) {
return new GatewayResponse("{}", headers, 500);
}
}
}
When I run sam local start-api and navigate to http://127.0.0.1:3000/hello, I get this error:
Secrets Manager can’t find the specified secret. (Service: AWSSecretsManager; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: 6881467f-d968-4f4e-ae60-7e3128124cc5)
com.amazonaws.services.secretsmanager.model.ResourceNotFoundException: Secrets Manager can’t find the specified secret. (Service: AWSSecretsManager; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: 6881467f-d968-4f4e-ae60-7e3128124cc5)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1632)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1304)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1058)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:743)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:717)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.doInvoke(AWSSecretsManagerClient.java:2024)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.invoke(AWSSecretsManagerClient.java:2000)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.executeGetSecretValue(AWSSecretsManagerClient.java:878)
at com.amazonaws.services.secretsmanager.AWSSecretsManagerClient.getSecretValue(AWSSecretsManagerClient.java:853)
at helloworld.App.handleRequest(App.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:259)
at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:178)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)
But, it's the same code to get the secret that was given in the secrets manager. Is it not possible to connect to real AWS services from sam local? I had a similar issue with DynamoDB, but was able to get it working with by using DynamoDB Local.
Any suggestions on how to either connect to the real secrets manager or to fake it locally somehow?
When you run DynamoDB Local, it is actually running a mock DDB server in a thread (or as a local process depending on how you start it) within you running test process. Unfortunately, Secrets Manager and other AWS services do not offer an equivalent testing solution.
However, if you are getting back ResourceNotFoundException it seems likely that you were able to successfully connect to Secrets Manager. It may be possible that the connection to secrets manager is using a different account than the one in which you stored the secret. One way you can check which credentials the code is using is to use the STS get caller identity call.
I have to migrate a class from opensaml 2.6 to opensaml 3.1.1
Compiling I obtain some errors
1)
Element plaintextElement = getElementAssertion(inputBean);
String xml = XMLHelper.prettyPrintXML(plaintextElement);
I can't find the class XMLHelper in the new version.
2)
DefaultBootstrap.bootstrap();
builderFactory = Configuration.getBuilderFactory();
Configuration.getMarshallerFactory().getMarshaller(assertion).marshall(assertion);
I can'f find class DefaultBootstrap and I can't find a class Configuration with the methods getBuilderFactory(), getMarshallerFactory()
3)
BasicCredential credential = new BasicCredential();
Now the contructor new BasicCredential() is not visible.
I haven't found documentation with deprecation indication.
What must I do to port this class to the opensaml 3.1.1 version?
Not sure if you managed to upgrade to opensaml 3 already but since I came across this while attempting the upgrade myself I thought I'm gonna document what I found.
There's very little documentation as apparently it's not a priority for them at the moment (also mentioned here: OpenSaml3 Documentation), the most useful (even if by far not complete) page I found is this one: https://wiki.shibboleth.net/confluence/display/OS30/Initialization+and+Configuration
1) There's a class SerializeSupport with a method prettyPrintXML in lib net.shibboleth.utilities:java-support
2) Initialization is now done via InitializationService
e.g.
InitializationService.initialize();
You can retrieve the builder/marshallers via XMLObjectProviderRegistrySupport e.g.:
XMLObjectProviderRegistrySupport.getMarshallerFactory()
XMLObjectProviderRegistrySupport.getBuilderFactory()
XMLObjectProviderRegistrySupport.getUnmarshallerFactory()
Mind that opensaml is using the Java Service Provider API. In my case (using OSGi bundle org.apache.servicemix.bundles:org.apache.servicemix.bundles.opensaml) for parsing a SAML assertion I added the SPI config META-INF/services/org.opensaml.core.config.Initializer containing the following entries:
org.opensaml.core.xml.config.XMLObjectProviderInitializer
org.opensaml.core.xml.config.GlobalParserPoolInitializer
org.opensaml.saml.config.XMLObjectProviderInitializer
org.opensaml.saml.config.SAMLConfigurationInitializer
org.opensaml.xmlsec.config.XMLObjectProviderInitializer
EDIT: The above worked in a test but did not run in the OSGi container. Workaround for OSGi: OpenSAML3 resource not found 'default-config.xml' in OSGi container
If you use the standard libraries (org.opensaml:opensaml-core, org.opensaml:opensaml-saml-api, org.opensaml:opensaml-saml-impl, ...) you may not need to add any SPI config as the jars already contain SPI configs with a standard configuration for initialization.
3) There's a class BasicCredential in lib org.opensaml:opensaml-security-api. I don' see an alternative to providing a key during initalization.
I am learning how to use the OS3 for development. This is one example to convert base 64 saml request to SAMLObject in V3 version. Hope it can help you.
The project see the github repository
public class SAMLToolkit {
public static SAMLObject convertBase64ToSaml(String base64Str) {
byte[] decodedBytes = new byte[0];
try {
decodedBytes = Base64.decode(base64Str);
} catch (Base64DecodingException e) {
e.printStackTrace();
return null;
}
InputStream is = new ByteArrayInputStream(decodedBytes);
//is = new InflaterInputStream(is, new Inflater(true));
try {
InitializationService.initialize();
Document messageDoc;
BasicParserPool basicParserPool = new BasicParserPool();
basicParserPool.initialize();
messageDoc = basicParserPool.parse(is);
Element messageElem = messageDoc.getDocumentElement();
Unmarshaller unmarshaller = XMLObjectProviderRegistrySupport.getUnmarshallerFactory().getUnmarshaller(messageElem);
assert unmarshaller != null;
return(SAMLObject) unmarshaller.unmarshall(messageElem);
} catch (InitializationException e) {
e.printStackTrace();
return null;
} catch (XMLParserException e) {
e.printStackTrace();
return null;
} catch (UnmarshallingException e) {
e.printStackTrace();
return null;
} catch (ComponentInitializationException e) {
e.printStackTrace();
return null;
}
}
}
I'm trying to build SIP application using JAIN SIP 1.2 and the NIST implementation on android.
I have rebuilt jain-sip-api-1.2.jar and jain-sip-ri-1.2.1111.jar from source, and renamed javax -> jain_javax and gov.nist.javax -> jain_gov.nist.jain_javax. I tested the jar files on textclient example on standard java without problem. However, when I run it on Android I still get the error:
"The Peer SIP Stack: jain_gov.nist.jain_javax.sip.SipstackImpl could not be instantiated. Ensure the Path Name has been set".
Did I miss anything here?
It is not sufficient to rename the packages. JAIN-SIP has internal references to some classes by their original package name "gov.nist". You should also double check all your code to rename any "gov.nist" references such as the prefix for the stack classes.
Android has built-in an older version of JAIN-SIP which is taking over some of the existing references to those "gov.nist" classes. It's not an exported API, so not quite obvious. That's why it may behave differently on desktop machines. Post you code and full error messages/debug logs if you need more help.
Sovled. Jain Sip is using log4i-1.2.x.jar which does not work properly on Android. There are lots of discussion on Internet how to make log4j working on Android but none of them works for me. I have removed all log4j related code from Jain Sip source and now the sip stack is working properly on Android.
I am using JAIN-SIP-1-2-164. Here is the app code:
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.text.ParseException;
import java.util.*;
import android.os.Handler;
import jain_javax.sip.*;
import jain_javax.sip.address.*;
import jain_javax.sip.header.*;
import jain_javax.sip.message.*;
public class SipLayer implements SipListener {
private SipStack sipStack;
private SipFactory sipFactory;
private Properties properties;
private String local_ip;
int listen_port;
/** Here we initialize the SIP stack. */
public SipLayer(int listen_port) {
try {
setUsername(username);
this.local_ip = InetAddress.getLocalHost().getHostAddress();;
this.listen_port = listen_port;
// Create the SIP factory and set the path name.
this.sipFactory = SipFactory.getInstance();
this.sipFactory.setPathName("jain_gov.nist");
// Create and set the SIP stack properties.
this.properties = new Properties();
this.properties.setProperty("jain_javax.sip.STACK_NAME", "stack");
this.properties.setProperty("jain_javax.sip.IP_ADDRESS", local_ip);
if(proxy != null)
this.properties.setProperty("jain_javax.sip.OUTBOUND_PROXY", proxy + ':' + server_port + '/' + protocol);
//DEBUGGING: Information will go to files textclient.log and textclientdebug.log
this.properties.setProperty("jain_gov.nist.javax.sip.TRACE_LEVEL", "32");
// this.properties.setProperty("jain_gov.nist.javax.sip.SERVER_LOG", "textclient.txt");
// this.properties.setProperty("jain_gov.nist.javax.sip.DEBUG_LOG", "textclientdebug.log");
// Create the SIP stack.
this.sipStack = this.sipFactory.createSipStack(properties);
}
catch (Exception e) {
msgProc.processError("SipLayer failed: " + e.getMessage() + "\n");
}
}
}
Same code runs ok on java on a windows machine, but android emulator I got above mentioned error message.
I found that it failed in following Jain SIP 1.2 routine at "SipStack sipStack = (SipStack) sipStackConstructor.newInstance(conArgs);"
private SipStack createStack(Properties properties)
throws PeerUnavailableException {
try {
// create parameters argument to identify constructor
Class[] paramTypes = new Class[1];
paramTypes[0] = Class.forName("java.util.Properties");
// get constructor of SipStack in order to instantiate
Constructor sipStackConstructor = Class.forName(
getPathName() + ".jain_javax.sip.SipStackImpl").getConstructor(
paramTypes);
// Wrap properties object in order to pass to constructor of
// SipSatck
Object[] conArgs = new Object[1];
conArgs[0] = properties;
// Creates a new instance of SipStack Class with the supplied
// properties.
SipStack sipStack = (SipStack) sipStackConstructor.newInstance(conArgs);
sipStackList.add(sipStack);
String name = properties.getProperty("jain_javax.sip.STACK_NAME");
this.sipStackByName.put(name, sipStack);
return sipStack;
} catch (Exception e) {
String errmsg = "The Peer SIP Stack: "
+ getPathName()
+ ".jain_javax.sip.SipStackImpl"
+ " could not be instantiated. Ensure the Path Name has been set.";
throw new PeerUnavailableException(errmsg, e);
}
}
Any suggestion or how to debug further?
I have a strange problem.
Using wsimport I generated als JAX-WS Code from a WSDL (in a dedicated eclipse java project). This works fine in JDK6 without any external dependencies (running in Eclipse)
I have second project where I once used Apache CXF. If I copy the Code described in 1.) into this project, suddenly not the JDK executes the JAX-WS stuff (files I generated), but rather Apache CXF.
How can I prevent Apache CXF "running" the JAX-WS stuff. (Problem is, CXF Fails to run the code...). I also completely do not understand how Apache CXF discovers these classes. I did not register them anywere?
Thank you very much!
Markus
Apache CXF (cxf-rt-frontend-jaxws-*.jar to be precise) registers itself as a JAX-WS provider in the JVM. Inside the aforementioned JAR there is a file named: /META-INF/services/javax.xml.ws.spi.Provider with the following contents:
org.apache.cxf.jaxws.spi.ProviderImpl
If you now look at javax.xml.ws.spi.FactoryFinder#find method you will discover that JDK searches the CLASSPATH for the presence of javax.xml.ws.spi.Provider file and falls back to default Sun implementation if not available. So you have two options to force fallback:
either remove cxf-rt-frontend-jaxws-*.jar from CLASSPATH
or override javax.xml.ws.spi.Provider file provided by CXF to point to fallback location
The second option is actually a bit easier. Simply create:
/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider
file (assuming you are using Maven) with the following contents:
org.apache.cxf.jaxws.spi.ProviderImpl
That's it, tested with javax.xml.ws.Endpoint#publish.
For the default implementation put:
com.sun.xml.internal.ws.spi.ProviderImpl
inside /src/main/resources/META-INF/services/javax.xml.ws.spi.Provider
I tried the other and I just couldn't make it work at all, so to set CXF if it was not set to CXF, I just override the delegate inside the service.
try {
loc = this.getClass().getResource(wsdlResource);
QName qName = new QName( wsTargetNamespace, wsName );
service = new YourWS(loc, qName);
Field delegateField = Service.class.getDeclaredField("delegate"); //ALLOW CXF SPECIFIC SERVICE DELEGATE ONLY!
delegateField.setAccessible(true);
ServiceDelegate previousDelegate = (ServiceDelegate) delegateField.get(service);
if (!previousDelegate.getClass().getName().contains("cxf")) {
ServiceDelegate serviceDelegate = ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance())
.createServiceDelegate(loc, qName, service.getClass());
log.info("The " + getClass().getSimpleName() + " delegate is changed from " + "[" + previousDelegate + "] to [" +
serviceDelegate +
"]");
delegateField.set(service, serviceDelegate);
}
port = service.getYourWSSoap();
The standard finding mechanisms don't seem to work nicely in OSGi (*).
There are two ways I've gotten to work forcing the service to pick up the CXF implementation of javax.xml.ws.spi.Provider:
the approach of setting delegate by reflection given in EpicPandaForce's answer to this question (https://stackoverflow.com/a/31892305/109079)
calling the lower-level JaxWsProxyFactoryBean; this seems to avoid all calls to the javax.xml.ws.spi.FactoryFinder included with Java which is the root of the problem
Here is an example of the latter, for less intrepid coders who prefer not reflectively changing private fields:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getClientFactoryBean().getServiceFactory().setWsdlURL(WinRmService.WSDL_LOCATION);
factory.setServiceName(WinRmService.SERVICE);
factory.setEndpointName(WinRmService.WinRmPort);
// factory.setFeatures(...); // if required
Service winrm = factory.create(WinRm.class);
Client client = ClientProxy.getClient(winrm);
A couple of notes:
Passing a URL as above, rather than the simpler factory.setWsdlURL(String) may be needed if the WSDL is a resource on the classpath (avoid unresolvable bundle://... URLs for classpath items)
You may need additional bundles for features (such as addressing)
(*) As for why the finding mechanisms don't work in most OSGi containers, check out this little bit of nasty in Oracle Java's FactoryFinder:
private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader";
private static boolean isOsgi() {
try {
Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME);
return true;
} catch (ClassNotFoundException ignored) {
}
return false;
}
OSGi = Glassfish? Fishy indeed!
I had a similar problem. In my case I had to use org.apache.cxf.jaxws.spi.ProviderImpl for JAX-WS stuff (creating webservice endpoints etc.) and com.sun.xml.internal.ws.spi.ProviderImpl for publishing endpoints on com.sun.net.httpserver.HttpsServer.
I managed to solve this by creating my own provider which extends javax.xml.ws.spi.Provider and using it instead of the default one.
package provider;
import java.net.URL;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.ws.Endpoint;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.spi.Provider;
import javax.xml.ws.spi.ServiceDelegate;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import org.w3c.dom.Element;
public class MyProvider extends Provider
{
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
public ServiceDelegate createServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class serviceClass)
{
try {
return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createServiceDelegate(wsdlDocumentLocation, serviceName, serviceClass.getClass());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public Endpoint createEndpoint(String bindingId, Object implementor)
{
try {
return ((Provider) Class.forName("com.sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createEndpoint(bindingId, implementor);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public Endpoint createAndPublishEndpoint(String address, Object implementor)
{
try {
return ((Provider) Class.forName("com.sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createAndPublishEndpoint(address, implementor);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public EndpointReference readEndpointReference(Source eprInfoset)
{
try {
return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).readEndpointReference(eprInfoset);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public <T> T getPort(EndpointReference endpointReference, Class<T> serviceEndpointInterface, WebServiceFeature... features)
{
try {
return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).getPort(endpointReference, serviceEndpointInterface, features);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
public W3CEndpointReference createW3CEndpointReference(String address, QName serviceName, QName portName, List<Element> metadata, String wsdlDocumentLocation, List<Element> referenceParameters)
{
try {
return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createW3CEndpointReference(address, serviceName, portName, metadata, wsdlDocumentLocation,
referenceParameters);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Then simply create:
/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider
file (assuming you are using Maven) with the following contents:
package.MyProvider
Knowing nothing of web services, I'm just trying to call some "isAlive" service that is described by a wsdl.
This seems to me like something that should take no more than 2-5 lines of code but I can't seem to find anything but huge long examples involving 3rd party packages etc.
Anyone has any ideas? If it is always suppose to be long maybe a good explanation as to why it has to be so complicated will also be appreciated.
I'm using Eclipse and the wsdl is SOAP.
JDK 6 comes with jax-ws, everything you need to develop a client for a web service.
I'm unable to find some simple enough examples to post , but start at https://jax-ws.dev.java.net/
Edit: here's a simple example - a client for this web service: http://xmethods.com/ve2/ViewListing.po?key=427565
C:\temp> md generated
C:\temp>"c:\Program Files\Java\jdk1.6.0_17"\bin\wsimport -keep -d generated http://www50.brinkster.com/vbfacileinpt/np.asmx?wsdl
Create PrimeClient.java which look like:
import javax.xml.ws.WebServiceRef;
import com.microsoft.webservices.*;
//the above namespace is from the generated code from the wsdl.
public class PrimeClient {
//Cant get this to work.. #WebServiceRef(wsdlLocation="http://www50.brinkster.com/vbfacileinpt/np.asmx?wsdl")
static PrimeNumbers service;
public static void main(String[] args) {
try {
service = new PrimeNumbers();
PrimeClient client = new PrimeClient();
client.doTest(args);
} catch(Exception e) {
e.printStackTrace();
}
}
public void doTest(String[] args) {
try {
System.out.println("Retrieving the port from the following service: " + service);
PrimeNumbersSoap pm = service.getPrimeNumbersSoap();
System.out.println("Invoking the getPrimeNumbersSoap operation ");
System.out.println(pm.getPrimeNumbers(100));
} catch(Exception e) {
e.printStackTrace();
}
}
}
Compile and run:
C:\temp>"c:\Program Files\Java\jdk1.6.0_17"\bin\javac -cp generated PrimeClient.java
C:\temp>"c:\Program Files\Java\jdk1.6.0_17"\bin\java -cp .;generated PrimeClient
Retrieving the port from the following service: com.microsoft.webservices.PrimeN
umbers#19b5393
Invoking the getPrimeNumbersSoap operation
1,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
There are plugins for IDE's which generate the needed code to consume a web service for you.
After the plugin generates you the base methods you simply call a web service like that:
TransportServiceSoap service = new TransportServiceLocator().getTransportServiceSoap();
service.getCities();
Have a look at http://urbas.tk/index.php/2009/02/20/eclipse-plug-in-as-a-web-service-client/
There are three ways to write a web service client
Dynamic proxy
Dynamic invocation interface (DII)
Application client
Example for Dynamic Proxy Client
import java.net.URL;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
import dynamicproxy.HelloIF;
public class HelloClient {
public static void main(String[] args) {
try {
String UrlString = "Your WSDL URL"; //
String nameSpaceUri = "urn:Foo";
String serviceName = "MyHelloService";
String portName = "HelloIFPort";
System.out.println("UrlString = " + UrlString);
URL helloWsdlUrl = new URL(UrlString);
ServiceFactory serviceFactory =
ServiceFactory.newInstance();
Service helloService =
serviceFactory.createService(helloWsdlUrl,
new QName(nameSpaceUri, serviceName));
dynamicproxy.HelloIF myProxy =
(dynamicproxy.HelloIF)
helloService.getPort(
new QName(nameSpaceUri, portName),
dynamicproxy.HelloIF.class);
System.out.println(myProxy.sayHello("Buzz"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I hope , this would solve your question.
The easiest I've found so far to use is the Idea IntelliJ wizard which - using Metro libraries - generate a very small code snippet which works fine with Java 6.