Connect XPage with OpenOffice - xpages

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

Related

Mule Issue : More than one JAXBContext

We are facing one issue in our Mule Adapter related to JAXB context, needed some opinion on the same
We are using xpath to evaluate some expressions in the choice blocks in our adapter like below for instance,
<choice doc:name="Choice">
<when expression="//env:abc/env:Body/ref:dataelement/ref:/ref:element" evaluator="xpath">
......
</when>
Now, this works perfectly fine in our application but the problem arises when one of other team uses this Adapter as a jar in their application.
When they try to use this adapter, they are getting below error,
Message : More than one object of type class javax.xml.bind.JAXBContext registered but only one expected.
Type : org.mule.api.registry.RegistrationException
Code : MULE_ERROR--2
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/registry /RegistrationException.html.
After debugging with the help of loggers etc, we narrowed down to the choice block used above which is causing this particular issue. Also, googled a bit and found one of the posts pointing out the same issue.
Also, to confirm we commented out the choice block having xpath expression and the flow went ahead but broke again where was xpath used in some other way.
https://www.mulesoft.org/jira/browse/MULE-5926
Can anyone please suggest any suitable workaround to resolve this issue?
I agree with you. It is an unresolved issue in Mule.
One solution we have implemented is not define the jaxb context in the config you are providing in the jar file.
Along with the jar file, give instructions to the end application using it, to include the JAXB packages in their JAXB Context object definition.
This way there will be only one JAXB context and it will work smoothly.
Hope this helps.
This is a bit late however the solution that worked was
<mulexml:jaxb-context name=“JAXB_Context“ packageNames=“org.example.test1:org.example.test2“ doc:name=“JAXB Context1“ />
Please note that there must be no space between package names.
Thanks to: http://dominikbial.de/quicktipp-working-with-more-than-one-package-name-in-a-jaxb-context-config-in-mule-esb/
As of now we cannot add more than one JAXBContext in mule. As an alternative you can write your custom transformer.
I implemented something like
public interface MyAppJaxbObj2XmlComponent<I,O> extends
MyAppComponent<I,O>,Callable {
public O marshal(I input) throws Exception;
}
Abstart transformer
public abstract class AbstractMyAppJaxbObj2XmlComponent<I,O> implements
MyAppJaxbObj2XmlComponent<I,O>{
private Class<I> inputType;
public AbstractMyAppJaxbObj2XmlComponent(){
this.inputType = (Class<I>) new TypeToken<I>(getClass())
{}.getRawType();
}
public AbstractMyAppJaxbObj2XmlComponent(Class<I> type){
this.inputType = type;
}
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
I input = eventContext.getMessage().getPayload(inputType);
O output = marshal(input);
return output;
}
}
Your flow transformer this will load your needed jaxb during startup.
#Component
public class MyFlowJaxbObj2XmlComponent extends
AbstractMyAppJaxbObj2XmlComponent<RequestPayloadType,String> {
#PostConstruct
public void init() {
//Load your schema during startup
}
}
You can also implement a fluid interface as an alternative for this.

Call a Java Agent from a Java Class in XPages

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"

How to set up a managed bean to work with Notes document

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

Making a servlet "Public"?

I finally got my test servlet working from this thread?
Calling HttpServlet class from xpages client side script and regular notes forms?
The issue that remains is I am being asked to login. But my final servlet will need to run without logging in. I have my acl set to Read public document and Write public documents for anonymous.
What I don't know how to do is to make the serlet public access. Other design documents have an "Available to Public Access users" property but I am seeing no such property for java files. Would this be set somewhere else? Maybe in my IServletFactory perhaps?
I don't know why I was required to log in before but it looks like it is now working. The only thing that is requred is that Read Public Public Document be enabled.
This is a bit concerning since it at least appears there is no way to make some servlets non-public. In my case it won't be an issue but it could be an issue for others.
Also what I noticed is that if you change the Public Access acl setting, it looks like you need to rebuild your servlets for some reason or the servlets won't run. When I get a chance I will open a ticket with notes support for both of these issues.
For those wanting to execute a servlet, I suggest this article:
http://8b30b0.wordpress.com/2013/02/04/creating-a-basic-domino-servlet/#comments
But here is a much more simplifed version of IServletFactory that might be easier to understand and get working.
package test;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import com.ibm.designer.runtime.domino.adapter.ComponentModule;
import com.ibm.designer.runtime.domino.adapter.IServletFactory;
import com.ibm.designer.runtime.domino.adapter.ServletMatch;
public class TestFactory implements IServletFactory {
private ComponentModule module;
public ServletMatch getServletMatch(String contextPath, String path)
throws ServletException {
System.out.println("TestFactory:getServletMatch");
String servletPath = "";
String pathInfo = path;
return new ServletMatch(getWidgetServlet(),servletPath,pathInfo);
}
public void init(ComponentModule arg0) {
System.out.println("TestFactory:init");
this.module = arg0;
}
public Servlet getWidgetServlet() throws ServletException {
return module.createServlet("com.pnc.cld.HelloWorld", "testServlet",null);
}
}

Can somedy explain me the TAB SAMPLE (gwtp)?

I am using GWTP. I did the nested presenter tutorial. But there is no tutorial for the SAMPLE TAB application (the one with the admin tab appearing if you switch to the admin mode). Can somebody explain me the main concepts of this application ? Tkx.
Update: Update: Now you can download the workable sample Maven project from here: gwtp-sample-tab.zip
I used the tabbed presenter feature successfully in my project (I found the sample code didn't compile as well). I think the first thing is to make it work, and then learn it and feel the benefits gradually :)
Here is the steps I did:
1) Copy the following files
BaseTab.java
BaseTabPanel.java
SimpleTab.java
SimpleTabPanel.java
SimpleTab.ui.xml
SimpleTabPanel.ui.xml
UiModule.java
from the sample code to you project. For example, I copied to this package: com.widenhome.web.client.ui. Also please remember to configure UiModule in ClientGinjector class.
2) Create a normal presenter (MyPresenter) via GWTP eclipse plugin
3) Change EventBus import this in the presenter
import com.google.web.bindery.event.shared.EventBus;
4) Make sure the MyPresenterView.ui.xml has the following code or similar:
<g:HTMLPanel>
<npui:SimpleTabPanel ui:field="tabPanel" />
<g:SimplePanel ui:field="contentPanel" />
</g:HTMLPanel>
5) Change the presenter to extend TabContainerPresenter instead of Presenter
public class MyPresenter extends
TabContainerPresenter<MyPresenter.MyView, MyPresenter.MyProxy>
6) Define several variables in MyPresenter, or you can just copy/paste the following code:
/**
* This will be the event sent to our "unknown" child presenters, in order
* for them to register their tabs.
*/
#RequestTabs
public static final Type<RequestTabsHandler> TYPE_RequestTabs = new Type<RequestTabsHandler>();
/**
* Fired by child proxie's when their tab content is changed.
*/
#ChangeTab
public static final Type<ChangeTabHandler> TYPE_ChangeTab = new Type<ChangeTabHandler>();
/**
* Use this in leaf presenters, inside their {#link #revealInParent} method.
*/
#ContentSlot
public static final Type<RevealContentHandler<?>> TYPE_SetTabContent = new Type<RevealContentHandler<?>>();
7) Change the constructor of MyPresenter to use the variables:
#Inject
public MyPresenter(final EventBus eventBus, final MyView view, final MyProxy proxy) {
super(eventBus, view, proxy, TYPE_SetTabContent, TYPE_RequestTabs, TYPE_ChangeTab);
}
8) Now we can start to create tab presenters, (e.g MyFirstTabPresenter). Just create a normal presenter again via GWTP eclipse plugin
9) In MyFirstTabPresenter, change MyProxy to let it 'extends' TabContentProxyPlace instead of ProxyPlace
10) Create #TabInfo method, please see javadoc of #TabInfo annotation, you can also use other ways here. For example, I did this:
#TabInfo(container = MyPresenter.class)
static TabData getTabLabel(ClientGinjector ginjector) {
return new TabDataBasic("My First Tab", 0);
}
11) In revealInParent() method of MyFirstTabPresenter class, please make sure it has the following code or similar:
#Override
protected void revealInParent() {
RevealContentEvent.fire(this, MyPresenter.TYPE_SetTabContent, this);
}
That's all related to Tabbed presenter configurations. Now you can add some logic to load some data to show in MyFirstPresenter's view.
I hope this can help you to start with GWTP Tabbed presenter, please let me know any issues you have, I will edit answer gradually and perfect it so that it can help more people to get started with it.
BTW, I also posted this to my blog to help more people on this.
Thanks,
Jiakuan
It doesn't even compile. The only way to trigger multiple presenters in via Nested Presenters - which is tooooo complicated. I built a multiple presenter app with simple GWT History mechanism without any pain. This framework has made GWT History (s aimple mechanism) a very esoteric thing.

Resources