I'm able to call a Java agent in SSJS with the following code:
var db:NotesDatabase = session.getCurrentDatabase();
var agent:NotesAgent = db.getAgent("AgentName");
agent.run();
But what I'm wanting to do is to call a Java agent from a Java class? Is this possible? Thanks for any tips.
The interesting challenge is to get hands on the session and/or database inside your Java class. The class could be in your NSF, in a plug-in, or a jar in jvm/lib/ext.
You don't want to depend on where it came from, so you use dependency injection to provide them (which is a fancy word for: provide as parameter) something like:
public class Leon implements Serializable {
public void cleanerDoYourWork(Database db) {
Agent theProfessional = db.getAgent("acidAndGuns");
theProfessional.run();
theProfessional.recycle();
}
}
In case you don't get the pun, search IMDB for Leon :-)
Remark: In SSJS you don't need session.getCurrentDatabase();, it is already there as "database"
Related
I process messages from a queue. I use data from the incoming message to determine which class to use to process the message; for example origin and type. I would use the combination of origin and type to look up a FQCN and use reflection to instantiate an object to process the message. At the moment these processing objects are all simple POJOs that implement a common interface. Hence I am using a strategy pattern.
The problem I am having is that all my external resources (mostly databases accessed via JPA) are injected (#Inject) and when I create the processing object as described above all these injected objects are null. The only way I know to populate these injected resources is to make each implementation of the interface a managed bean by adding #stateless. This alone does not solve the problem because the injected members are only populated if the class implementing the interface is itself injected (i.e. container managed) as opposed to being created by me.
Here is a made up example (sensitive details changed)
public interface MessageProcessor
{
public void processMessage(String xml);
}
#Stateless
public VisaCreateClient implements MessageProcessor
{
#Inject private DAL db;
…
}
public MasterCardCreateClient implements MessageProcessor…
In the database there is an entry "visa.createclient" = "fqcn.VisaCreateClient", so if the message origin is "Visa" and the type is "Create Client" I can look up the appropriate processing class. If I use reflection to create VisaCreateClient the db variable is always null. Even if I add the #Stateless and use reflection the db variable remains null. It's only when I inject VisaCreateClient will the db variable get populated. Like so:
#Stateless
public QueueReader
{
#Inject VisaCreateClient visaCreateClient;
#Inject MasterCardCreateClient masterCardCreateClient;
#Inject … many more times
private Map<String, MessageProcessor> processors...
private void init()
{
processors.put("visa.createclient", visaCreateClient);
processors.put("mastercard.createclient", masterCardCreateClient);
… many more times
}
}
Now I have dozens of message processors and if I have to inject each implementation then register it in the map I'll end up with dozens of injections. Also, should I add more processors I have to modify the QueueReader class to add the new injections and restart the server; with my old code I merely had to add an entry into the database and deploy the new processor on the class path - didn't even have to restart the server!
I have thought of two ways to resolve this:
Add an init(DAL db, OtherResource or, ...) method to the interface that gets called right after the message processor is created with reflection and pass the required resource. The resource itself was injected into the QueueReader.
Add an argument to the processMessage(String xml, Context context) where Context is just a map of resources that were injected into the QueueReader.
But does this approach mean that I will be using the same instance of the DAL object for every message processor? I believe it would and as long as there is no state involved I believe it is OK - any and all transactions will be started outside of the DAL class.
So my question is will my approach work? What are the risks of doing it that way? Is there a better way to use a strategy pattern to dynamically select an implementation where the implementation needs access to container managed resources?
Thanks for your time.
In a similar problem statement I used an extension to the processor interface to decide which type of data object it can handle. Then you can inject all variants of the handler via instance and simply use a loop:
public interface MessageProcessor
{
public boolean canHandle(String xml);
public void processMessage(String xml);
}
And in your queueReader:
#Inject
private Instance<MessageProcessor> allProcessors;
public void handleMessage(String xml) {
MessageProcessor processor = StreamSupport.stream(allProcessors.spliterator(), false)
.filter(proc -> proc.canHandle(xml))
.findFirst()
.orElseThrow(...);
processor.processMessage(xml);
}
This does not work on a running server, but to add a new processor simply implement and deploy.
I have a button on an XPage where I want to connect to a remote OpenOffice instance. OpenOffice is started and is listening for a socket connection.
The onclick event of the button runs following SSJS:
oo = new com.test.OpenOffice();
oo.init("host=127.0.0.1,port=8107");
oo.openFile("C:\\TEMP\\Test.odt");
The code raises an excepction jva.lang.IlleagalStateException: NotesContext not initialized for the thread
The exception is raised within the method initof the class OpenOffice.
The relevant parts of the class OpenOffice is the following code:
public class DHOpenOffice implements Serializable {
private static final long serialVersionUID = -7443191805456329135L;
private XComponentContext xRemoteContext;
private XMultiComponentFactory xMCF;
private XTextDocument oTextDocument;
public DHOpenOffice() {
xRemoteContext = null;
xMCF = null;
oTextDocument = null;
}
public void init(String hostAdr) throws java.lang.Exception {
xRemoteContext = null;
XComponentContext xLocalContext = Bootstrap.createInitialComponentContext(null);
XUnoUrlResolver xUrlResolver = UnoUrlResolver.create(xLocalContext);
String sConnect = "uno:socket," + hostAdr + ",tcpNoDelay=0;urp;StarOffice.ServiceManager";
Object context = xUrlResolver.resolve(sConnect);
xRemoteContext = UnoRuntime.queryInterface(XComponentContext.class, context);
xMCF = xRemoteContext.getServiceManager();
}
The code line Object context = xUrlResolver.resolve(sConnect); is the one that raises the exception.
Why is this happing? What is the reason for this exception and how can I resolve the situation?
N.B.: The class code runs smoothly in a standalone application. The error occurs only when the code is started by a SSJS code.
It looks like a threading issue. There are a number of things you can go and try:
Wrap the whole interaction into a custom class and use it from a managed bean instead of calling it from SSJS
Make sure not to hand over any Notes objects into the custom class, only your own
Check if the Open Document Toolkit would be sufficient to do the operations you are interested in, so you don't need to run OO
let us know how it goes
Update
Try to get outside the standard XPages cycle. One way is to deploy a custom plug-in servlet:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class OpenOfficeServlet extends HttpServlet {
// Your code goes here
}
You need to get the plugin.xml right:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension point="org.eclipse.equinox.http.registry.servlets">
<servlet alias="/ooproxy" class="com.yourcompany.OpenOfficeServlet" />
</extension>
</plugin>
Then you could e.g. post a JSON structure or a serializable Java object to the servlet with the data and process it there (async if necessary). You deploy such a plug-in using the updatesite.nsf
Thanks to the answer of #stwissel I was able to solve the problem (he pointed me to the right direction).
I could solve the problem with a simple OSGI plug-in. The servlet approach solved the problem, too, but for me the OSGI plug-in was easier to use.
So these are the steps to create the plug-in
start a new plugin project
copy the open office jar files into the project and include them into the build path
copy the custom class that uses the UNO API into the plug-in
create a feature project for the plugin
create an update site
deploy the plugin via an update site
The following site where also quite helpfull:
Creating an XPages Library
Wrap an existing JAR file into a plug-in
As EF 5.0 is already having UnitOfWork pattern implemented so I want to it instead of creating my own IUnitOfWork classes for maintaining transactions. But most of the examples I found on internet are using Separate UnitOfWork instead of EF directly.
I'm trying to implement this using IoC (castle windsor). Could you please provide some samples or direction on implementing this.
Thanks in advance
Sai
You didn't provide any details about your current Windsor setup or what UoW looks like in EF5 (I don't use it), but based on this [1] it appears they have an IUnitOfWork interface implemented on their db context class. So this appears to be pretty straightforward to leverage in a dependency injection pattern driven by Windsor. You'll first want to register the IUnitOfWork interface and implementation with the container. There's a variety of ways to register components in Windsor. I prefer installers [2]... so you'll end up with something like this:
public class YourInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IUnitOfWork>().ImplementedBy<YourDbContext>());
}
}
Then you have this injected into your application's services in some fashion such as:
public class YourService
{
public YourService(IUnitOfWork uow)
{
// rock out
}
}
[1] http://dumians.wordpress.com/2013/04/13/how-to-use-repository-and-unit-of-work-patterns-with-entity-framework/
[2] http://docs.castleproject.org/Default.aspx?Page=Installers&NS=Windsor&AspxAutoDetectCookieSupport=1
I would like to set up a managed bean that manages a Notes document in Notes view where I store application preferences in (e.g. path on server to store attachments, application title, which logo to display etc)
Has anyone an example for such a bean and how I should use it?
Current I load a SSJS library an place everything in application scope or session scope variables.
Here is a simple example for such a managed bean.
First create a Java class. I called it "Config". It reads the first document in view "Config" and puts at instantiation time (=first call) the items in java fields. Doing this you can recycle the domino objects after reading all items and have the values in memory then.
package de.leonso;
import java.io.Serializable;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.View;
import com.ibm.xsp.extlib.util.ExtLibUtil;
public class Config implements Serializable {
private static final long serialVersionUID = 1L;
private String applicationTitle;
// ... other private fields
public Config() throws NotesException {
Database db = ExtLibUtil.getCurrentSession().getCurrentDatabase();
View view = db.getView("Config");
Document doc = view.getFirstDocument();
applicationTitle = doc.getItemValueString("ApplicationTitle");
// ... read all other items and store them in private fields
doc.recycle();
view.recycle();
db.recycle();
}
public String getApplicationTitle() {
return applicationTitle;
}
// ... getters for other private fields
}
Next define this Java class as a managed bean in faces-config.xml file:
<faces-config>
<managed-bean>
<managed-bean-name>config</managed-bean-name>
<managed-bean-class>de.leonso.Config</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
</faces-config>
You can use as scope "application" (instance per server) or "session" (instance per user).
Then you can use the config bean in JavaScript:
#{javascript:var titel = config.applicationTitle; ...}
or Expression Language:
#{config.applicationTitle}
That should give you a good starting point to develop an advanced version of a config bean.
The application-scoped bean is definitely a good way to go for this. Once you get more comfortable with Java, you might want to consider using a VariableResolver instead or even an OSGi plugin if some of those options are server-wide. I've also posted an XSnippet for retrieving values from xsp.properties, which may also be appropriate for some settings http://openntf.org/s/retrieve-property-from-xsp.properties-in-nsf-server-or-notes.ini
I think i understood how CDI works and in order to dive deep in it, i would like to try using it with something real world example. I am stuck with one thing where i need your help to make me understand. I would really appreciate your help in this regard.
I have my own workflow framework developed using Java reflection API and XML configurations where based on specific type of "source" and "eventName" i load appropriate Module class and invoke "process" method on that. Everything is working fine in our project.
I got excited with CDI feature and wanted to give it try with workflow framework where i am planning inject Module class instead of loading them using Reflection etc...
Just to give you an idea, I will try to keep things simple here.
"Message.java" is a kind of Transfer Object which carries "Source" and "eventName", so that we can load module appropriately.
public class Message{
private String source;
private String eventName;
}
Module configurations are as below
<modules>
<module>
<source>A</source>
<eventName>validate</eventName>
<moduleClass>ValidatorModule</moduleClass>
</module>
<module>
<source>B</source>
<eventName>generate</eventName>
<moduleClass>GeneratorModule</moduleClass>
</module>
</modules>
ModuleLoader.java
public class ModuleLoader {
public void loadAndProcess(Message message){
String source=message.getSource();
String eventName=message.getEventName();
//Load Module based on above values.
}
}
Question
Now , if i want to implement same via CDI to inject me a Module (in ModuleLoader class), I can write Factory class with #Produce method , which can do that. BUT my question is,
a) how can pass Message Object to #Produce method to do lookup based on eventName and source ?
Can you please provide me suggestions ?
Thanks in advance.
This one is a little tricky because CDI doesn't work the same way as your custom solution (if I understand it correctly). CDI must have all the list of dependencies and resolutions for those dependencies at boot time, where your solution sounds like it finds everything at runtime where things may change. That being said there are a couple of things you could try.
You could try injecting an InjectionPoint as a parameter to a producer method and returning the correct object, or creating the correct type.
There's also creating your own extension of doing this and creating dependencies and wiring them all up in the extension (take a look at ProcessInjectionTarget, ProcessAnnotatedType, and 'AfterBeanDiscovery` events. These two quickstarts may also help get some ideas going.
I think you may be going down the wrong path regarding a producer. Instead it more than likely would be much better to use an observer especially based on what you've described.
I'm making the assumption that the "Message" transfer object is used abstractly like a system wide event where basically you fire the event and you would like some handler defined in your XML framework you've created to determine the correct manager for the event, instantiate it (if need be), and then call the class passing it the event.
#ApplicationScoped
public class MyMessageObserver {
public void handleMessageEvent(#Observes Message message) {
//Load Module based on above values and process the event
}
}
Now let's assume you want to utilize your original interface (I'll guess it looks like):
public interface IMessageHandler {
public void handleMessage(final Message message);
}
#ApplicationScoped
public class EventMessageHandler implements IMessageHandler {
#Inject
private Event<Message> messageEvent;
public void handleMessage(Message message) {
messageEvent.fire(message);
}
}
Then in any legacy class you want to use it:
#Inject
IMessageHandler handler;
This will allow you to do everything you've described.
May be you need somthing like that:
You need the qualifier. Annotation like #Module, which will take two paramters source and eventName; They should be non qualifier values. See docs.
Second you need a producer:
#Produces
#Module
public Module makeAmodule(InjectionPoint ip) {
// load the module, take source and eventName from ip
}
Inject at proper place like that:
#Inject
#Module(source="A", eventName="validate")
Module modulA;
There is only one issue with that solution, those modules must be dependent scope, otherwise system will inject same module regardles of source and eventName.
If you want to use scopes, then you need make source and eventName qualified parameters and:
make an extension for CDI, register programmatically producers
or make producer method for each and every possible combinations of source and eventName (I do not think it is nice)