Why RDF4J won't work in Bluemix Cloud Foundry - java

RDF4J is an apache open source graph db that i use often on my PC.
It comes with 2 webApp : RDF4J-server and RDF4J-workbench (a user interface)
On my PC i push the 2 wars in the same Tomcat and everything is ok.
I begin an experiment to push these apps in the Bluemix Cloud (which is a cloud foundry)
The java-tomcat boilerplate wants a single War in order to associate it with the URL of the new container, so i create 2 separate apps in 2 java containers :
1 for RDF4J-Server,
1 for RDF4J-WB.
Both apps are running and i can access to default pages.
In WB, the form 'connect to server' allows you to give the URL of the server you want to work with.
I enter the URL https://rdf4jmyserver.mybluemix.net. WB finds the server but loops on the form, unable to open a db.
I suppose first that a split in 2 containers can be an issue, but i do the following test :
-run RD4J workbench in a local Tomcat on my machine
-connect to the rdf4Jmyserver on the cloud
-> Everything is ok !
So the pb is not to run in 2 separate places.
I investigate a bit more, dowload the source code (thanks open source) and recompile with more and more debug traces .
After a long day, i found the bug in the Workbench code, despite the fact this code is as old as the previous version Sesame: Nobody catch it .
Philosophy for today :
Bluemix works well, but pushing an app in the cloud can reveal old weakness !
I will give the patch in a next post.

Explanation :
When the selected server by workbench is not the default one ( which is supposed to be on the same root url ), the program establish a new cookie to keep trace of the new choice.
The wrong code is here , in CookieHandler.java :
private void initCookie(final Cookie cookie, final HttpServletRequest req) {
final String context = req.getContextPath();
cookie.setPath(null == context ? "/" : context);
}
}
The url is something like https://rdf4j-mywb.mybluemix.net
So, when there is no context for the cookie, the software wants to add a / .
But this code is false.
Going back to the java API, one can see :
public java.lang.String getContextPath()
Returns the portion of the request URI that indicates the context of the request.
The context path always comes first in a request URI.
The path starts with a "/" character but does not end with a "/" character.
For servlets in the default (root) context, this method returns "".
The container does not decode this string.
So this old buried bug can be fixed by :
// cookie.setPath(null == context ? "/" : context);
cookie.setPath(context.isEmpty()? "/" : context);
And now, Workbench works well on Bluemix !
HTH
PS: as rdf4Jserver runs also in a cloud container, datas on disk can disappear when container is reset. Another job has to be done : using an objectstore service in Bluemix. ( another day)

Related

Change REST URL depending on called URL

I currently have a problem with a REST service: The basic construction is the following: On my Tomcat there are running 2 applications (my new REST service (S1) and another application (S2) which also offers REST calls). The Applications should work together so that S1 can send requests to S2. It works fine if I use hard coded URLs in S1 to call S2. But the problem is that the path of the applications are changing due to different ports or configurations. The changes apply to both applications since they are both on the same Tomcat server.
Basically the 2 Paths look similar, starting e.g. with http://localhost:8080/ or http://sys-example:8034/. So if I call S1 on an specific Path, the application should fetch the URL and build its own basePath to reach S2 on the same Server. How can I create a method which gets me the path where my service is called. IS there a way to use ServletContext or is there a better way?
Currently this is my code in S1 to reach the service in S2
String path = configMap.get("basePath").toString();
//configMap is a HashMap which contains Data from an config file
//the result of get("basePath") looks like this: http://localhost:8080
path = path.concat("/otherService/rest/action/login");
If you are sure that the 2 servlets will run in the same Tomcat installation and, moreover, in the same context, I suggest using the direct interaction.
Please check the link at this URL.
If I got you right, you are saying that you run the services in different environments, e.g. production, development, local etc., which means host and port differ. The relative paths to your services remain the same, though.
Then, it is absolutely ok to hard-code the relative paths since they don't change. The host and port, however, should be configurable. You could load them from the database, in case you have access to your database before you need those data.
Another solution might be to configure host and port within your web container. If you should use Tomcat as your web container, create a properties file and load it when the app is being bootstrapped.
EDIT:
Other answers suggest to resolve the path from the request object. I disadvise doing that for the following reasons:
There might be use cases where you don't have a request. There might be (now or in future) other interfaces to your services than via HTTP
You should not rely on what URL to call depending on the request coming in, since you have no control over that values. Think of Reverse Proxies or Load Balancer.
You can extract the REST call using an URI object. Example:
URI u = URI.create("http://www.example.com:8080/rest/service/call");
String restPath = u.getPath();
System.out.println(restPath);
This way, you can append the REST url easily to S2. I hope that helps :)
You can fetch the required details from HttpServletRequest object.
The below code must give you the required details. I have not tested this, but this should get you started.
StringBuffer url = request.getRequestURL();
String uri = request.getRequestURI();
String host = url.substring(0, url.indexOf(uri));
I think request.getRequestURL() is what you want

Randomly Channel.Connect.Failed error when calling to a Java server from Flex application using AMF protocol

I have a project published in the Internet that is used by thousands of users every day. Basically, I'm using a server in AmazonAWS with the server part compiled in Java 6 running in a Tomcat. I'm using AMF to publish the services and my client is built in Flex 4.6 using Flash Builder to generate the classes to connect to the AMF services. The code I'm using to connect to the services is this:
public var cpcService:RemotingServicesImpl;
private function callService():void
{
FlexGlobals.topLevelApplication.callingService=true;
encryptedSession=ResourcesUtil.buildSessionId(globalSettings.sessionId, globalSettings);
var responder:Responder=new Responder(gameStateLoaded, gameStateFailed);
var token:AsyncToken=cpcService.getGameState(encryptedSession, taskKey);
token.addResponder(responder);
}
private function gameStateFailed(ev:FaultEvent=null):void
{
DisplayUtil.trackErrorInfoEvent("FATAL - FatalError", "getGameState-" + FlexGlobals.topLevelApplication.mainView.currentState, ev, encryptedSession);
}
private function gameStateLoaded(ev:Object):void
{
// my fantastic code when everything is ok
}
Normally, everything is ok and my application is working, but some calls (like 1 every 500) are not working, I know it because in the trackErrorInfoEvent function I'm registering an event in the Google Analytics, so I know this is randomly happening. This is the error:
faultCode = "Client.Error.MessageSend"
faultDetail = "Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed: url: 'https://appcog.cognifit.com/messagebroker/amf'"
faultString = "Send failed"
rootCause = (null)
Of course the URL is correct and is working all times.
I have seen in some blogs that adding this line:
<add-no-cache-headers>false</add-no-cache-headers>
the problem is fixed, but I have that line in my config file and is still happening.
I have checked my server logs and I have no records for service interruptions at any time.
I really apreciate any help, thanks in advance!

Why does weblogic's "not found" behavior change after the first attempt?

I'm using Weblogic 10.3.5. I work on a large legacy enterprise application with Struts (1.x) mapped as the default servlet.
Background
A bit of legacy convolution to start: each enterprise customer has a "subscriber ID" which their users must provide at login in addition to their username and password. Subscriber IDs are numeric and always at least four digits, usually five. If you go to mysite.com/, you are presented with a three-field login page: subscriber ID, username, and password.
Our largest enterprise customers didn't like that, so many years ago we introduced skinned login pages: go to mysite.com/12345, where 12345 is your subscriber ID. We'll prepopulate and hide the subscriber ID field, and skin the login page with the enterprise customer's logo and color scheme.
Years later, we had 100+ servlet mappings, one for each subscriber. Every new customer required a software deployment to add the servlet mapping, so our implementations team was hamstrung by the dev team's deployment schedule, which in turn was limited by our large enterprise customers' need to budget time for user acceptance testing.
To address that, we changed the URL: mysite.com/login/12345, where /login/* is mapped to a single servlet that accepts any subscriber ID. We kept the old servlet mappings around so that existing customers didn't have to change the URL, but that left two annoyances:
A few hundred lines of cruft in web.xml
As a developer or QA, it's annoying to have to know whether this is an old subscriber or a new one before you know what URL to use to log in. Try to use the old method for a new subscriber? You get a 404 page.
Here's what I did
We had a pre-existing custom 404 page, correctly defined in web.xml and behaving exactly as expected. I updated it with the following code, right at the top:
<%
if (request.getRequestURI().matches("^/[\\d]{4,}$")) {
// probably someone trying to log in with the old-style URL
response.sendRedirect(String.format("/login%s", request.getRequestURI()));
return;
}
%>
This worked like a charm, until I noticed one oddity:
Here's what's wrong
The very first time I try to visit a URL that should result in a 404 but will be redirected because it matches the regex, it doesn't redirect. With my debugger, I've determined that the reason is that request.getRequestURI() returns "/errors/404error.jsp" rather than "/12345" like I would expect, resulting in the regex not matching and our normal 404 page being served to the user.
My first thought was that something was telling the browser to redirect to the 404 page, but Chrome Dev Tools "Network" tab indicates that is not the case.
After it fails that first time, my change works every subsequent time until the application server restarts.
If I hit /login/12345 first it loads fine. Any subsequent attempt to hit /12345 will work fine, so it seems like it might have something to do with the login servlet not being fully initialized until after the first request. Weblogic is closed source, so I'm not able to dig into what's happening.
Here's my question
I know it's a pretty weird thing I'm doing; I'm open to other approaches. But the question is this: what's causing the different request URI on the first attempt, and how do I fix it? I've scoured the HttpServletRequest object in the debugger and I don't see any indication of the real request URI.

Why is this URL not opened from Play! Framework 1.2.4?

I have a URL in my Play! app that routes to either HTML or XLSX depending on the extension that is passed in the URL, with a routes line like :-
# Calls
GET /calls.{format} Call.index
so calls.html renders the page, calls.xlsx downloads an Excel file (using Play Excel module). All works fine from the browser, a cURL request, etc.
I now want to be able to create an email and have the Excel attached to it, but I cannot pull the attachment. Here's the basic version of what I tried first :-
public static void sendReport(List<Object[]> invoicelines, String emailaddress) throws MalformedURLException, URISyntaxException
{
setFrom("Telco Analysis <test#test.com>");
addRecipient(emailaddress);
setSubject("Telco Analysis report");
EmailAttachment emailAttachment = new EmailAttachment();
URL url = new URL("http://localhost:9001/calls.xlsx");
emailAttachment.setURL(url);
emailAttachment.setName(url.getFile());
emailAttachment.setDescription("Test file");
addAttachment(emailAttachment);
send(invoicelines);
}
but it just doesn't pull the URL content, it just sits there without any error messages, with Chrome's page spinner going and ties up the web server (to the point that requests from another browser/machine don't appear to get serviced). If I send the email without the attachment, all is fine, so it's just the pulling of the file that appears to be the problem.
So far I've tried the above method, I've tried Play's WS webservice library, I've tried manually-crafted HttpRequests, etc. If I specify another URL (such as http://www.google.com) it works just fine.
Anyone able to assist?
I am making an assumption that you are running in Dev mode.
In Dev mode, you will likely have a single request execution pool, but in your controller that send an email, you are sending off a second request, which will block until your previous request has completed (which it won't because it is waiting for the second request to respond)...so....deadlock!
The resaon why external requests work fine, is because you are not causing the deadlock on your Play request pool.
Simple answer to your problem is to increase the value of the play.pool in the application.conf. Make sure that it is uncommented, and choose a value greater than 1!
# Execution pool
# ~~~~~
# Default to 1 thread in DEV mode or (nb processors + 1) threads in PROD mode.
# Try to keep a low as possible. 1 thread will serialize all requests (very useful for debugging purpose)
play.pool=3

Flex+JPA/Hibernate+BlazeDS+MySQL how to debug this monster?

Ok so I'm making a "simple" web app using the technologies from the topic, recently I found http://www.adobe.com/devnet/flex/articles/flex_hibernate.html so I'm following it and I try to apply it to my app, the only difference being I'm working on a Mac and I'm using MAMP for the database (so no command line for me).
The thing is I'm having some trouble with retrieving/connecting to the database.
I have the remoting-config.xml, persistance.xml, a News.java class (my Entity), a NewsService.java class, a News.as class - all just like in the tutorial. I have of course this line in one of my .mxmls:
<mx:RemoteObject id="loaderService" destination="newsService" result="handleLoadResult(event)" fault="handleFault(event)" showBusyCursor="true" />
And my remoting-config.xml looks like this (well part of it):
<destination id="newsService">
<properties><source>com.gamelist.news.NewsService</source></properties>
</destination>
NewsService has a method:
public List<News> getLatestNews() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
EntityManager em = emf.createEntityManager();
Query findLatestQuery = em.createNamedQuery("news.findLatest");
List<News> news = findLatestQuery.getResultList();
return news;
}
And the named query is in the News class:
#Entity
#Table(name="GLT_NEWS")
#NamedQueries({
#NamedQuery(name="news.findLatest", query="from GLT_NEWS order by new_date_added limit 5 ")
})
The handledLoadResult looks like this:
private function handleLoadResult(ev:ResultEvent):void {
newsList = ev.result as ArrayCollection;
newsRecords = newsList.length;
}
Where:
[Bindable]
private var newsList:ArrayCollection = new ArrayCollection();
But when I try to trigger:
loaderService.getLatestNews();
nothing happens, newsList is empty.
Few things I need to point out:
1) as I said I didn't install mysql manually, but I'm using MAMP (yes, the server's running), could this cause some trouble?
2) I already have a "gladm" database and I have a "GLT_NEWS" table with all the fields, is this bad?
Basically the question is how am I suppose to debug this thing so I can find the mistake I'm making? I know that loadData() is executed (did a trace()), but I have no idea what happens with loaderService.getLatestNews()...
#EDIT: ok so I see I'm getting an error in the "fault handler" which says
"Error: Client.Error.MessageSend - Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 404: url: 'http://localhost:8080/WebContent/messagebroker/amf' - "
#EDIT2: Ok i solved the problem, as it turns out my ContextRoot was incorrect, the funny thing is I couldn't edit it by going to Project properties->Flex Server as it was uneditable! I had to find the .flexProject file and edit it (obviously my Flex Navigator didn't show it and by accident I noticed it was being filtered).
To answer your question as to, in general, debug this monster...here is what I do.
Set break points in my Java code
Start up the Java application server with the appropriate debug JVM properties set (e.g. -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n)
From Eclipse, I attach a remote debugger to the app server on the default port 8000. The Java Debugger will open up when a break point is hit.
Set breakpoints in my Flex application (or one of its modules).
From Eclipse (with Flash Builder) I launch a debug configuration for my Flex app. The Flex Debugger will open up when a break point is hit.
At this point I have two debuggers open and everything work great. Two other things I do:
a) extend the transaction system timeout, so it doesn't get trigger while I am sitting there think for a few minutes
b) use Charles Proxy (in reverse proxy mode) inbetween the client and server to watch the AMF traffic and view payloads, etc.
Hope this helps.
your error means you are not calling the server on the right way. Something is wrong there, the url the web.config file or other BlazeDS config files.

Categories