Jetty Bind DataSource in JNDI Context - eclipse

I would like to bind DataSource object to (eclipse) jetty's JNDI context programatically. I need for testing purpose. Here's a piece of code I have now:
server = new Server(SERVER_PORT);
webAppContext = new WebAppContext();
webAppContext.setResourceBase(".");
webAppContext.setContextPath("/" + SERVER_CONTEXT);
webAppContext.addEventListener(prepareServletContextListener());
webAppContext.addFilter(GuiceFilter.class, "/*", null);
webAppContext.addServlet(DefaultServlet.class, "/");
Resource r = new Resource(webAppContext,"jdbc/testDS",createDataSource());
server.setHandler(webAppContext);
server.start();
Of course the line with Resource isn't working.I have no idea how to bind it programatically to obtain sth similar to:
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/DSTest</Arg>
<Arg>
<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="Url">jdbc:mysql://localhost:3306/databasename</Set>
<Set name="User">user</Set>
<Set name="Password">pass</Set>
</New>
</Arg>
</New>
Any help would be greatly appreciated.

you need to add the defined resource object as attribute to the server object.
The following should work:
Resource r = new Resource("jdbc/testDS",createDataSource());
server.setAttribute("myDs", r);

I encountered the same issue and here is what I did to fix it:
server = new Server(PORT);
WebAppContext context = new WebAppContext();
context.setContextPath(CONTEXT);
context.setConfigurationClasses(new String[] { "org.eclipse.jetty.plus.webapp.PlusConfiguration",
"org.eclipse.jetty.webapp.FragmentConfiguration" });
// A filter needed by Guice, but this is independent
context.addFilter(GuiceFilter.class, "/*", 0);
PGSimpleDataSource simpleDataSource = new PGSimpleDataSource();
simpleDataSource.setDatabaseName("db-name");
simpleDataSource.setUser("user");
simpleDataSource.setPassword("pwd");
String jndiName = "jdbc/myDS";
Resource resource = new Resource("java:comp/env/" + jndiName, simpleDataSource);
server.setHandler(context);
// an event listener (because I use Guice, but this is independent)
GuiceServletConfig guiceServletConfig = new GuiceServletConfig();
context.addEventListener(guiceServletConfig);
server.start();
This requires to have the following additional libraries:
jetty-jndi
jetty-plus
I tested this code on Embedded Jetty 7 (7.6.10.v20130312)

The topic is old but I have encountered the same issue. Unfortunately existing answers provide no solution.
When you create a Resource specifying an instance of the DataSource, Jetty will not provide this instance when JNDI resource is requested. Instead constructor of Resource makes an attempt to transform the instance to some kind of "recipe" (javax.naming.Reference to be precise) that tells how to build the new instance of configuration with exact same internals.
It works well in case of basic classes but fails to recreate complex data structures (it failed with List<String> in my case). So you end up not getting:
the exact same instance (as you expect of a singleton)
the exact equivalent of the instance (as you expect of properly working JNDI)
I have implemented a wrapper that allows providing the instance specified when creating the Resource.
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
public class ExistingInstanceReference extends Reference implements ObjectFactory {
private Object instance;
private static final long serialVersionUID = -2718709718400909747L;
public ExistingInstanceReference() {
super(null);
}
public ExistingInstanceReference(Object instance) {
super(instance.getClass().getName(), ExistingInstanceReference.class.getName(), null);
this.instance = instance;
}
#Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
if (obj == null) {
return null;
}
ExistingInstanceReference reference = (ExistingInstanceReference) obj;
return reference.instance;
}
}
Note that this implementation fails to comply with Serializable interface as instance variable may contain non-serializable object.
Usage:
Resource r = new Resource(webAppContext, "jdbc/testDS", new ExistingInstanceReference(createDataSource()));
Please, consider this solution as a workaround because the real issue is still to be fixed somewhere in Jetty's sources. Unfortunately I have no time to trace this misbehavior to the root.
In addition, I had to set webAppContext.setParentLoaderPriority(true) because the webapp's classloader didn't see ExistingInstanceReference class in my setup.

Related

WildFly naming subsystem: how to bind to a java.util.Properties object

I intend to define a JNDI propery of the type java.util.Properties in the WildFly application server to read it from my application.
As described in the an older WildFly documentation one can create a global binding of the type object-factory. In the example is an optional environment tag to hold multiple key/value pairs. That would map exactly my desire to get a java.util.Properties when reading a JNDI resource.
The question is weather there is already an implementiation of javax.naming.spi.ObjectFactory to create a java.util.Properties object out of an object-factory binding or do I need to implement it myself and install it as a separate module (like it is described at mastertheboss.com/...)?
Ok, I just implemented it mysef.
package com.myorg.wildfly.objectfactory;
...
public class WildFlyPropertiesObjectFactory implements ObjectFactory
{
#Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception
{
Properties p = new Properties();
if(environment != null)
{
Set<?> keySet = environment.keySet();
for(Object key : keySet)
{
p.put(key, environment.get(key));
}
}
return p;
}
}
Clean&Build this single class into a JAR file wildfly-properties-objetfactory.jar
Add a module via jboss-cli.sh
module add --name=my.jndi.propertyreader --resource=wildfly-properties-objetfactory.jar --dependencies=javax.api
Create a naming binding via jboss-cli.sh
/subsystem=nameing/binding=java\:\/my_super_cool_jndi_name:add(binding-type=object-factory, module=my.jndi.propertyreader, class=com.myorg.wildfly.objectfactory.WildFlyPropertiesObjectFactory, environment=[key1=value1, key2=value2])
And in my application I can access it in an CDI bean via
public void test() {
Properties p = (Properties) new InitialContext().lookup("java:/my_super_cool_jndi_name");
System.out.printf("Properties: %s%n", p);
}
Or as shown in the mentioned link inject it as a direct dependency #Resource(lookup = "java:/my_super_cool_jndi_name") Properties p;
Works as a charm.

Problems while connecting to two MongoDBs via Spring

I'm trying to achieve to connect to two different MongoDBs with Spring (1.5.2. --> we included Spring in an internal Framework therefore it is not the latest version yet) and this already works partially but not fully. More precisely I found a strange behavior which I will describe below after showing my setup.
So this is what I done so far:
Project structure
backend
config
domain
customer
internal
repository
customer
internal
service
In configI have my Mongoconfigurations.
I created one base class which extends AbstractMongoConfiguration. This class holds fields for database, host etc. which are filled with the properties from a application.yml. It also holds a couple of methods for creating MongoClient and SimpleMongoDbFactory.
Furthermore there are two custom configuration classes. For each MongoDB one config. Both extend the base class.
Here is how they are coded:
Primary Connection
#Primary
#EntityScan(basePackages = "backend.domain.customer")
#Configuration
#EnableMongoRepositories(
basePackages = {"backend.repository.customer"},
mongoTemplateRef = "customerDataMongoTemplate")
#ConfigurationProperties(prefix = "customer.mongodb")
public class CustomerDataMongoConnection extends BaseMongoConfig{
public static final String TEMPLATE_NAME = "customerDataMongoTemplate";
#Override
#Bean(name = CustomerDataMongoConnection.TEMPLATE_NAME)
public MongoTemplate mongoTemplate() {
MongoClient client = getMongoClient(getAddress(),
getCredentials());
SimpleMongoDbFactory factory = getSimpleMongoDbFactory(client,
getDatabaseName());
return new MongoTemplate(factory);
}
}
The second configuration class looks pretty similar. Here it is:
#EntityScan(basePackages = "backend.domain.internal")
#Configuration
#EnableMongoRepositories(
basePackages = {"backend.repository.internal"}
mongoTemplateRef = InternalDataMongoConnection.TEMPLATE_NAME
)
#ConfigurationProperties(prefix = "internal.mongodb")
public class InternalDataMongoConnection extends BaseMongoConfig{
public static final String TEMPLATE_NAME = "internalDataMongoTemplate";
#Override
#Bean(name = InternalDataMongoConnection.TEMPLATE_NAME)
public MongoTemplate mongoTemplate() {
MongoClient client = getMongoClient(getAddress(), getCredentials());
SimpleMongoDbFactory factory = getSimpleMongoDbFactory(client,
getDatabaseName());
return new MongoTemplate(factory);
}
}
As you can see, I use EnableMongoRepositoriesto define which repository should use which connection.
My repositories are defined just like it is described in the Spring documentation.
However, here is one example which is located in package backend.repository.customer:
public interface ContactHistoryRepository extends MongoRepository<ContactHistoryEntity, String> {
public ContactHistoryEntity findById(String id);
}
The problem is that my backend always only uses the primary connection with this setup. Interestingly, when I remove the beanname for the MongoTemplate (just #Bean) the backend then uses the secondary connection (InternalMongoDataConnection). This is true for all defined repositories.
My question is, how can I achieve that my backend really take care of both connections? Probably I missed to set another parameter/configuration?
Since this is a pretty extensive post I apologise if I forgot something to mention. Please ask for missing information in the comments.
I found the answer.
In my package structure there was a empty configuration class (of my colleague) with the annotation #Configurationand #EnableMongoRepositories. This triggered the automatic wiring process of Stpring Data and therefore led to the problems I reported above.
I simply deleted the class and now it works as it should!

GWT Request Factory and Editor Framework Exception

When attempting to edit a new (proxy) entity using RequestFactoryEditorDriver.edit() I am getting the following error: "Exception caught: Attempting to edit an EntityProxy previously edited by another RequestContext". I am fairly sure that this is a result of my misunderstanding of the request factory/editor framework architecture. Here is the editor code that I think pertains to this problem:
public class OrgMaintenanceWidget extends Composite implements Editor<IOrgProxy> {
... other fields ...
private IOrgEditorDriver _orgEditorDriver;
interface IOrgEditorDriver extends RequestFactoryEditorDriver<IOrgProxy, OrgMaintenanceWidget> {}
public OrgMaintenanceWidget(final IClientFactory clientFactory) {
... widget initialization ...
_orgEditorDriver = GWT.create(IOrgEditorDriver.class);
_orgEditorDriver.initialize(_clientFactory.getRequestFactory().getEventBus(),
_clientFactory.getRequestFactory(), this);
}
#UiHandler("newButton")
public void onNewButtonClick(final ClickEvent clickEvent) {
_org = _clientFactory.getCache().getOrgCache().newOrg();
_orgEditorDriver.edit(_org, _clientFactory.getRequestFactory().orgRequestContext());
}
...
}
It's the "_orgEditorDriver.edit()" line that causes the exception. The "newOrg()" method is:
public IOrgProxy newOrg() {
return _clientFactory.getRequestFactory().orgRequestContext().create(IOrgProxy.class);
}
The RequestFactory is simply:
public interface IRequestFactory extends RequestFactory {
IOrgRequestContext orgRequestContext();
}
I am sure that I'm missing something fundamental about editing a new entity. When I edit an existing entity everything is fine ... the UI components are populated automatically, and flushing the editor back to the entity works very nicely. Here's the code that initiates editing for an existing entity:
#UiHandler("newButton")
public void onNewButtonClick(final ClickEvent clickEvent) {
_org = _clientFactory.getCache().getOrgCache().newOrg();
_orgEditorDriver.edit(_org, _clientFactory.getRequestFactory().orgRequestContext());
}
Any help would be greatly appreciated, and I'll try to publish any lessons learned.
This code:
_clientFactory.getRequestFactory().orgRequestContext().create(IOrgProxy.class);
Means:
Create new orgRequestContext()
Create new IOrgProxy using this context
Edit new IOrgProxy using this context, because as docs say: "Returns a new mutable proxy that this request can carry to the server, perhaps to be persisted.", it means that the proxy is edited by this request.
This code:
_orgEditorDriver.edit(_org, _clientFactory.getRequestFactory().orgRequestContext());
Means:
Again, create new orgRequestContext() (because each invocation of getRequestFactory().orgRequestContext() provides new instance of orgRequestContext()
"Start driving the Editor and its sub-editors with data." as docs say. But as a part of it, use passed orgRequestContext() to edit passed IOrgProxy instance, so that the proxy is editable.
Because the proxy was already edited while created by other RequestContext, you get the exception, because there is fundamental rule in RequestFactory, that proxy can be edited only by one RequestContext.
See also this thread.
I think you can't create an object with one RequestContext and then edit it with another one.
So you can solve this in two ways:
Persist the created object with the RequestContext you used when you created the object. The save method should return the persisted object and this persisted object can be passed to the editor with a fresh new RequestContext
Somewhere save the RequestContext you used for creating the object and pass it to the edit function of your Driver
Solution two could look something like this:
#UiHandler("newButton")
public void onNewButtonClick(final ClickEvent clickEvent) {
IOrgRequestContext ctx = _clientFactory.getRequestFactory().orgRequestContext();
_org = ctx.create(IOrgProxy.class);
_orgEditorDriver.edit(_org,ctx );
}

Can't insert new entry into deserialized AutoBean Map

When i try to insert a new entry to a deserialized Map instance i get no exception but the Map is not modified. This EntryPoint code probes it. I'm doing anything wrong?
public class Test2 implements EntryPoint {
public interface SomeProxy {
Map<String, List<Integer>> getStringKeyMap();
void setStringKeyMap(Map<String, List<Integer>> value);
}
public interface BeanFactory extends AutoBeanFactory {
BeanFactory INSTANCE = GWT.create(BeanFactory.class);
AutoBean<SomeProxy> someProxy();
}
#Override
public void onModuleLoad() {
SomeProxy proxy = BeanFactory.INSTANCE.someProxy().as();
proxy.setStringKeyMap(new HashMap<String, List<Integer>>());
proxy.getStringKeyMap().put("k1", new ArrayList<Integer>());
proxy.getStringKeyMap().put("k2", new ArrayList<Integer>());
String payload = AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(proxy)).toString();
proxy = AutoBeanCodex.decode(BeanFactory.INSTANCE, SomeProxy.class, payload).as();
// insert a new entry into a deserialized map
proxy.getStringKeyMap().put("k3", new ArrayList<Integer>());
System.out.println(proxy.getStringKeyMap().keySet()); // the keySet is [k1, k2] :-( ¿where is k3?
}
}
Shouldn't AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(proxy)).toString(); be getPayLoad()
I'll check the code later, and I don't know if that is causing the issue. But it did stand out as different from my typical approach.
Collection classes such as java.util.Set and java.util.List are tricky because they operate in terms of Object instances. To make collections serializable, you should specify the particular type of objects they are expected to contain through normal type parameters (for example, Map<Foo,Bar> rather than just Map). If you use raw collections or maps you will get bloated code and be vulnerable to denial of service attacks.
Font: http://www.gwtproject.org/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes

JAXB How to force xsi:type in array of subclasses? (JBoss 4.2.3)

(Please note; i'm completely new to webservices, so the following may be stupid/incorrect but please be patient)
In my WebServices' #WebMethod I'm returning an array of an abstract base class (JAXB annotated entities in JBoss 4.2.3).
Obviously unless the type information is encoded per array element this will fail...
So how do I ensure that JAXB adds the xsi:type attribute?
My WebService interface has the following annotation, and I've tried every legal combination:
#SOAPBinding(style = RPC, parameterStyle = WRAPPED, use = LITERAL)
the methods on this interface take x2 parameters annotated #WebParam(name="...", mode=IN)
Other methods with similar signatures that don't return a heterogeneous array work perfectly.
Some related things:
Looks like JBoss uses the types defined in the method signatures to decide what classes to load into the JAXBContext - if I change the return types to Object[] it throws an error stating that the AbstractBase class "nor any of its super class is known to this context." I've added dummy methods returning the specific subclasses so that the generated WSDL has a list of all of them.
when I try to write tests for this, all is ok for single elements, but JAXB throws an error for array types: unable to marshal type "[LAbstractBase;" as an element because it is missing an #XmlRootElement annotation
From code like that shown below (note: AbstractBase, ConcreteOne and ConcreteTwo all have #XmlRootElement annotations)
private static final Class<?>[] CLASSES_TO_BE_BOUND = new Class<?>[]{
//Note; adding AbstractBase[].class doesn't work either
AbstractBase.class, ConcreteOne.class, ConcreteTwo.class
};
#Test
public void testXsiTypeAttributeIsIncludedInHeterogeneousArray()
{
AbstractBase[] array = new AbstractBase[2];
array[0] = new ConcreteOne();
array[1] = new ConcreteTwo();
Marshaller marshaller = createMarshaller();
StringWriter sw = new StringWriter();
marshaller.marshal(array, sw);
String output = sw.toString();
Assert.assertTrue(output.contains("xsi:type=\""));
}
private Marshaller createMarshaller() throws Exception {
JAXBContext context = JAXBContext.newInstance(CLASSES_TO_BE_BOUND);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
return marshaller;
}
Ideally I'd like to be able to test some bits relating to arrays, but it's far more critical that I can get the type information encoded per element in the JBoss environment.
Edit: Own Answer
JBoss (4.2.3) is doing something clever, but not too clever - it will handle the returning of arrays but not polymorphic arrays. This threw me a bit as I tried to get this way of doing it working in my tests.
Instead of trying to solve the JBoss WebService issue I made my tests more comprehensive - making the array a member of a simple container class and then annotating the array's getter with:
#XmlElementRefs({
#XmlElementRef(type = ConcreteOne.class),
#XmlElementRef(type = ConcreteTwo.class)
})
public AbstractBase[] getItems() { /*...*/ }
Which worked, and returning this in the JBoss WebService also worked! Though I'm using:
#SOAPBinding(style = DOCUMENT, parameterStyle = BARE, use = LITERAL)
So it's not adding the xsi:type attribute, but document nodes are correctly tagged:
<ConcreteOne>...</ConcreteOne>
At some point I'll change the WebService to use RPC as I don't really like the single argument restriction, but for now this is working fine.