I have an interface like this:
#Remote
public interface ClientDataAccessRemote
And the EJB implements it:
#Stateless
public class ClientDataAccess implements ClientDataAccessRemote
And in the remote client I can access the EJB with this:
#EJB
private static ClientDataAccessRemote clientDataAccess;
This is everything I did and it works. The client and the EJB reside on the same server. Would it still work if they were separated? And how would the container find the EJB with that interface? I implemented this with Netbeans and I didnĀ“t have to specify any locations or anything like that. How does this work?
Unfortunatelly #EJB annotation works for local (single JVM) injections only. For separate hosts you need to fallback to plain JNDI lookup.
AFAIK there are some proprietary non-portable solutions to perform remote dependency injections, like for WebLogic server (here), but I wouldn't go that way.
JNDI lookup works but is overly complicated and quite ugly:
you need to know server vendor and add its client libraries to your app's dependencies,
you pollute application with:
cryptic vendor-specific URI formats
vendor-specific naming service port numer (often defaults to 1099, but who knows for sure...)
vendor-specific jndi-name pattern
Here is example lookup for bean hosted on remote JBoss 4.x instance:
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
properties.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
properties.setProperty(Context.PROVIDER_URL, "localhost:1099");
InitialContext context = null;
ClientDataAccessRemote cl = null;
try {
context = new InitialContext(properties);
cl = (ClientDataAccessRemote) context.lookup("ClientDataAccess/remote");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Given your EJB is part of EAR you need to prefix name of EJBean with name of EAR:
cl = (ClientDataAccessRemote) context.lookup("MyEAR/ClientDataAccess/remote");
Above example is JBoss specific, I'm not even sure if it will work with JBoss 5.x series without modifications.
Apparently EJB 3.1 specification brings some unification to jndi naming, but I haven't got pleasure to work with it yet.
If this example scared you a little, maybe a better solution would be exposing your EJB as web services (SOAP or REST style).
It brings problems of it's own, but is portable at least.
Related
I am using WAS and DB2 and my Application is coded in Java.
If I create a connection pooling in websphere Application server, then do I need to change anything in Java code? or Websphere will handle all connection pooling concept?
To take advantage of connection pooling provided by WebSphere Application Server, you need to obtain connections from data source. First configure the data source and assign a jndiName to it.
Then you can use resource injection to define a resource reference for it and inject into a Java EE component, for example,
#Resource(lookup = "jdbc/ds1", name = "java:comp/env/jdbc/ds1ref")
DataSource ds1;
or look it up in JNDI, for example,
DataSource ds = InitialContext.doLookup("java:comp/env/jdbc/ds1ref");
Always make sure to close connections that obtain from the data source when you are done with them so they can go back to the pool,
Connection con = ds.getConnection();
try {
...
} finally {
con.close();
}
If your application needs to access any JDBC vendor APIs (not part of the JDBC specification), use the JDBC wrapper pattern (unwrap method). For example,
OracleConnection oraCon = con.unwrap(OracleConnection.class);
Other than that, usage of connection pooling should be pretty much transparent.
I have a connection to an MS Access 2000 database defined in wildfly 9.0.2. Works fine. Using the commandline UCanAccess, I run it with -Dfile.encoding=ISO-8859 in order to have national characters (Norwegian) displayed correctly, on Ubuntu. On OS X the commandline displays national characters correctly without any jre-option. However the Wildlfy instance is also running on OS X, and does not display national characters correct (currently they're just written to console in a simple test) Using UcanAccess-driver in any java-based sql client like DBeaver or SQLSquirrel "just works" when it comes to character set. However, querying the database via JPA and wildfly, the national characters are replaced with '?'.
So, there is a way to specify a praticular "opener" on the jdbc-url for Jackcess:
......mdb;jackcessOpener=ucaextension.JackcessWithCharsetISO88591Opener
where the "opener" looks like this:
public class JackcessWithCharsetISO88591Opener implements JackcessOpenerInterface {
public Database open(File f, String pwd) throws IOException {
DatabaseBuilder db = new DatabaseBuilder(f);
db.setCharset(Charset.forName("ISO-8859-1"));
try {
db.setReadOnly(false);
return db.open();
} catch (IOException e) {
db.setReadOnly(true);
return db.open();
}
}
}
(yes, the exception handling should at least issue a warning.)
So I packaged this as a jar-file (maven), removed the old connection, driver and module definitions in wildfly. Then I added this jar-file, along with the others for the ucanaccess module (ucanaccess itself, hsqldb etc), recreated the driver and connection, now with the opener-parameter, and re-reployed the war using it. But wildfly complains:
Caused by: java.lang.ClassNotFoundException: ucaextension.JackcessWithCharsetISO88591Opener from [Module "com.ucanaccess:main" from local module loader #1060b431 (finder: local module finder #612679d6 (roots: /Users/jonmartinsolaas/Local/wildfly-9.0.2.Final/modules,/Users/jonmartinsolaas/Local/wildfly-9.0.2.Final/modules/system/layers/base))]
So clearly the url-parameter has been picked up, but the class is not found, even though it is deployed along with the other jars for the driver. The class is actually in the jar-file. But do I need to reference it from any other MANIFEST.INF classpath in the other jars or something?
The case, it seems, is that various consoles doesn't show the national characters. That, and the fact that I actually have to specify charset running on the ubuntu commandline, led me to believe there was a problem, and actually displaying data in the browser and not in the logging console showed just that. No need for a jackcess "opener" for a specific character set.
This seems like a simple question to me:
I have a project where I automatically generate a Spring-WS WSDL, something like this:
<sws:dynamic-wsdl id="service"
portTypeName="Service"
locationUri="/Service/"
targetNamespace="http://location.com/Service/schemas/Mos">
<sws:xsd location="classpath:/META-INF/Service.xsd"/>
</sws:dynamic-wsdl>
Is there a way, on application context startup, to output the generated address of the wsdl, including context, location, etc? This would be handy if our integration tests start to fail, we can see if the location of the WSDL has changed.
As far as I know, you can find the WSDL at http://yourHost/yourServletContext/beanId.wsdl. In your case, beanId is 'service'.
Check out 3.7. Publishing the WSDL in the Spring-WS documentation for more information about this subject.
If you plan to expose your XSD's as well, the beanId.xsd (or, in my case the method name in the #Configuration class) format will be used. For instance:
private ClassPathResource exampleXsdResource = new ClassPathResource("example.xsd");
#Bean public SimpleXsdSchema example() {
return new SimpleXsdSchema(exampleXsdResource);
}
This exposes an XSD at http://yourHost/yourServletContext/example.xsd.
I'm trying to develop a stand-alone client app that uses web services in a Glassfish container (Metro). About all I have to work from is a wsdl for the wervices I'm trying to use. The wsdl is rife with all kinds of 'wsp:Policy' tags. Looks like IssuedToken, Trust13, ecryption are all utilized.
So I generated some code from netbeans and JAX-WS. Everything went well, but when trying to run the client I get:
'WST0029:STS location could not be obtained from either IssuedToken or from client configuration for accessing the service http://localhost:8080/ ....'
That's when it occured to me that I know nothing about WSS. It doesn't look like any code was generated to deal with security. So, I'll have to go from scratch.
So where to start? Books? Tutorials?
TIA
Metro applies the policy in runtime from either the WSDL or the wsit-client.xml config file. That's why no code is generated related to policies. According to this post it is not possible at the moment to do programatically.
This tutorial explains pretty well some of the things you can do with WSS, and though everything do probably not apply in this case it's still a good read.
The simplest way I've found of generating a client with WSS support is by using the wsimport script from Metro:
cd metro/bin/
mkdir src target
./wsimport.sh -s src -d target -extension -Xendorsed -verbose YourService.wsdl
Then install Metro into your application server (copy the libs to the correct places or run the ant script):
ant -f metro-on-glassfish.xml
Then put your local WSDL file in your classpath (e.g. your resource folder), so Metro can get it at runtime to apply the policies from your generated YourService class:
private final static URL YOURSERVICE_WSDL_LOCATION;
// This is enough, you don't need the wsdlLocation attribute
// on the #WebServiceClient annotation if you have this.
static {
YOURSERVICE_WSDL_LOCATION =
CustomerService.class.getClassLoader().getResource("YourService.wsdl");
}
public YourService() {
super(YOURSERVICE_WSDL_LOCATION,
new QName("http://tempuri.org/", "YourService"));
}
And if you want WS-Addressing you might need to add the feature manually to your binding method (Metro has never generated it for me, so I always have to add it myself).
#WebEndpoint(name = "WSHttpBinding_IYourService")
public IYourService getWSHttpBindingIYourService() {
WebServiceFeature wsAddressing = new AddressingFeature(true);
IYourService service =
super.getPort(new QName("http://xmlns.example.com/services/Your",
"WSHttpBinding_IYourService"), IYourService.class,
wsAddressing);
return service;
}
BACKGROUND:
Current Grails application has to interact w/ a 'legacy' web service
from a third party vendor - (systinet) Used the Apache CXF
Wsdl2Java tool to generate complex types and service interfaces.
Pretty standard stuff so far and this works perfectly from Java.
After writing some test classes and main() methods to
exercise the Java code, and providing a thin layer above for a
simplified interface, I wanted to call this code from Grails app.
Specifically, Grails controllers, services, quartz jobs ,and the
like. However, this is where things got interesting.
First stack trace from Grails CXF plug-in it was causing a FileNotFoundException. Beyond not needing to load a WSDL definition - since I already successfully ran CXF's Wsdl2Java tool, it seems there is something I'm missing here. Tried substituting a file:/// url***for the WSDL and got another exception.
At the end of all this -- removing plug-ins of any sort, I reconfigured the project with the CXF dependencies by hand** and now got a MarshallingException, essentially from the CXF-generated code! Which by the way executes perfectly from a Java class.
Someone I am sure must've come across this issue in your Grails integrations. As always your guidance is most appreciated!
1)Why in the Grails application, does the runtime attempt to parse the wsdl ? Also, note JDK versions are same java version "1.6.0_12".
2) Any CLASSPATH workarounds anyone can suggest? I guess an alternative approach is to re-write the Java middle layer calls with GroovyWS but that would be quite an effort - given number of services and the custom types the vendor has baked in.
static {
URL url = null;
try {
url = new URL("http://mydevhost:9080/wasp/bmc-security/ctsa/person");
} catch (MalformedURLException e) {
System.err.println("Can not initialize the default wsdl from server");
// e.printStackTrace();
}
WSDL_LOCATION = url;
}
/* static {
URL url = null;
try {
url = new URL( "file:///C:/Projects/beta/workspace/reqmgr3/wsdl/Person.wsdl" );
url.getPath();
} catch (MalformedURLException e) {
System.err.println("Can not initialize the default wsdl from file system");
// e.printStackTrace();
}
WSDL_LOCATION = url;
} */
`
****Stack traces
INFO: No Trust Decider configured for Conduit ...
Aug 11, 2010 6:26:16 PM org.apache.cxf.transport.http.HTTPConduit finalizeConfig
INFO: No Basic Auth Supplier configured for Conduit '...
Aug 11, 2010 6:26:16 PM org.apache.cxf.transport.http.HTTPConduit prepare
INFO: Chunking is set at 2048.
Aug 11, 2010 6:26:16 PM org.apache.cxf.phase.PhaseInterceptorChain doIntercept
INFO: Interceptor has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Marshalling Error: com.systinet.wsdl.com.bmc.security.ess.webservice.holder.ArrayOfLog
inPairHolder is not known to this context
at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:132)
at org.apache.cxf.jaxb.io.XMLStreamDataWriter.write(XMLStreamDataWriter.java:42)
at org.apache.cxf.jaxb.io.XMLStreamDataWriter.write(XMLStreamDataWriter.java:30)
at org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:73)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:148)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:215)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:122)
at $Proxy44.login(Unknown Source)
...
... 2 more
UPDATE 15-Aug:
Decided, out of both modularity and expediency, to put this code into separate WAR project, which will offer its ltd. services, rather than expose the original vendor web services, which are too unwieldy.
This project will be pure Java and leverages the Metro 2.0.1 runtime, which is around 16mb.
Calling the Java-based middleware services from Grails now becomes possible, after clearing out the lib and src/java folders -- basically just installed ws-client plugin and setup local services such as the following:
import groovyx.net.ws.WSClient
import org.grails.plugins.wsclient.service.WebService
class LocalPersonService {
WebService webService
groovyx.net.ws.WSClient _proxy
static final String PERSON_WSDL_URL = "http://localhost:9090/pri/PersonServicePort?wsdl"
def transactional = false
def getPersonDetails( String customerId, User userAccount, String userCredential ) {
// must cache the proxy
if ( _proxy == null ) {
print( "init proxy. Parsing wsdl..." )
try {
_proxy = webService.getClient(PERSON_WSDL_URL)
}
catch ( Throwable tr ) { println( tr.getMessage() ) }
}
// method shall return a (com.siventures.example.service.PersonDetails)
return _proxy.getPersonDetails( customerId, userAccount, userCredential, ... )
}