How to do logging in servlets deployed to jboss 7.1 - servlets

I am writing a simple web app with one servlet and my System.out.println statements (in my servlet) do not show up in the server.log file which for me is located at
C:\jboss-as-7.1.1.Final\jboss-as-7.1.1.Final\standalone\log
So, I'm thinking that maybe I need to set up some kind of logging or something. I am completely clueless on this.
I have tried to research log4j as an option but the more I research the more confused I get.
I need a step by step approach on this. If anyone could please help I would be so thankful.

The simplest to start is IMHO using java.util.logging framework. You don't need any special application dependency. It just works.
Example usage in a servlet:
import java.util.logging.Logger;
private final Logger LOGGER = Logger.getLogger(getClass().getName());
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
final PrintWriter writer = resp.getWriter();
writer.println("Logging message with SEVERE importance level");
LOGGER.severe("Test log message with level SEVERE");
writer.close();
}
Look on GitHub for a full example servlet.
To enable all log-levels for your application, you can use JBoss CLI (jboss-cli.sh / jboss-cli.bat). Here is example, assuming your application is under org.jboss.test package:
connect
/subsystem=logging/console-handler=CONSOLE:write-attribute(name=level,value=ALL)
/subsystem=logging/logger=org.jboss.test:add(level=ALL)
quit

Related

HttpServletResponse getWriter() write function starts to throw nullpointer exception after a few days?

I have implemented the following servlet post function on a jetty server. In the HttpServletResponse, it will just write some string.
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write("some json string");
response.getWriter().flush();
}
Everything was fine in the beginning. But after some time (a few days; i was not using it and just kept the jetty server running), the servlet starts to throw null pointer exception on the line response.getWriter().write("some json string");
java.lang.NullPointerException
at org.eclipse.jetty.server.ResponseWriter.write(ResponseWriter.java:246)
I don't know what went wrong. But after a restart of the jetty server, the problem was gone. Do you guys know why?
To answer the NullPointerException
java.lang.NullPointerException
at org.eclipse.jetty.server.ResponseWriter.write(ResponseWriter.java:246)
It seems that you gave the Writer a null String.
See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.22.v20191022/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java#L246
The part where you say Jetty stops working after a few days is likely because you have a process on your machine that is periodically cleaning out the system temp directory, removing content out from underneath Jetty.
See: Jetty stops responding after some period of time
The NullPointerException is like is likely because the write failed and you didn't check for that fact.
HttpServletResponse.getWriter() returns a java.io.PrintWriter.
Using the various .write() methods will never throw an error or exception.
You need to use .checkError() method to know when the write has failed.
This is an old-school API decision on java.io.PrintWriter that is actually quite awkward.
See: PrintWriter and PrintStream never throw IOExceptions

how to call a sling servlet through osgi bundle inside CQ5

I just created a Sling servlet through maven.packaging as - "bundle", then I installed it inside system console of CQ5.
My bundle shows me Active state and all the required packages ..exported successfully.
but I when I call this bundle to use the servlet... nothing happened.
It doesn't give me response.
Is there a better way..to create a sling servlet and create a OSGI bundle,so that I can install it as a bundle in CQ5 to call the servlet from the component.
You can create SlingSerlvet like this.
#SlingServlet(
paths={"/services/myapp/LoginController/validateUser","/services/myapp/LoginController/logout"})
#Properties({
#Property(name="service.pid", value="com.xxx.xxx.controller.LoginController",propertyPrivate=false),
#Property(name="service.description",value="Validates the user", propertyPrivate=false),
#Property(name="service.vendor",value="xxx Tech", propertyPrivate=false)
})
public class LoginController extends SlingAllMethodsServlet{
private static final long serialVersionUID = 1L;
#Override
protected void doPost(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
}
#Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
}
}
To Call this servlet in browser just type the URLS "/services/myapp/LoginController/validateUser"
And "/services/myapp/LoginController/logout" As you may already know that a serlvet can have multiple URLS.
This is a working piece of Code.
Make sure that your URL Mappings i.e paths(in Sling/CQ5) starts with /services
also you can also create bundle using a dedicated Eclipse for CQ5 CRXDE Eclipse instead of Maven bundle.
It's much easier to use but it is a bit slow. Download Here
Bingo.. finally I am able to call a sling sevlet bundled as OSGI bundle and deployed in CQ's system console.
later I called this OSGI bundle fire a post request and this time able to get the response.
here is a very nice and very explanatory tutorial from Scott that explain every and each steps of my problem.
http://scottsdigitalcommunity.blogspot.in/2013/06/posting-form-data-to-adobe-cq-using.html
and the sample code or sample application link can be found from here -
http://helpx.adobe.com/experience-manager/using/custom-sling-servlets.html
follow the above link step by step and you end up with the victory.
I followed each steps and successfully called OSGI bundle's servlet through component inside CRXDE.
and finally not to forget to thanks Scott.... thanks Scott for the explanation !!!

jboss deployment issue - can not visit servlet

I am trying to write a simple web application and deploy on jboss EAP 6. The application is named "webapp" and I was able to build and deploy it to jboss. The context root is /webapp.
I was able to then visit localhost:8080/webapp and it returns a "Hello World" printed from the defaulted index.jsp that was generated by eclipse at /src/main/webapp.
However, when I tried to actually visit the servlet at localhost:8080/webapp/sessionsetup I got the following error:
JBWEB000065: HTTP Status 404 - /webapp/sessionsetup
JBWEB000309: type JBWEB000067: Status report
JBWEB000068: message /webapp/sessionsetup
JBWEB000069: description JBWEB000124: The requested resource is not available.
Below is my simple code for the servlet:
#WebServlet("/sessionsetup")
public class SessionSetup extends HttpServlet{
private static final Logger log = LoggerFactory.getLogger(SessionSetup.class);
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info(this.toString());
log.info("Do get method is called");
response.setContentType("text/xml");
PrintWriter printer = response.getWriter();
printer.println("<html>");
printer.println("<head>" + "</head>");
printer.println("<body>");
printer.println("<h1>" + "Welcome! You are in session setup" + "</h1>");
printer.println("</body>");
printer.println("</html>");
printer.close();
}
}
Could anyone comment on where I might miss something? Is there a way to find some log information no this error? I tried to look for server.log at /standalone/log but couldn't find anything.
There can be 2 reasons
(1) you can configure your standalone.xml in jboss server
virtual-server name="default-host" enable-welcome-root="false">
use false instead of true in enable-welcome-root
(2)
you have not done mapping of controller properly
Problem resolved. It appears to be an issue with the web.xml - once this is removed, the servlet is available.
The actual problem should be the way how it was deployed(Run time name) in the jboss.
So if you try to access the application on that it should works.
Runtime Name: Name by which the deployment should be known within a server's runtime. This would be equivalent to the file name of a deployment file, and would form the basis for such things as default Java Enterprise Edition application and module names. This would typically be the same as 'name', but in some cases users may wish to have two deployments with the same 'runtime-name' (e.g. two versions of "foo.war") both available in the deployment content repository, in which case the deployments would need to have distinct 'name' values but would have the same 'runtime-name'.
This is just my experience about how this problem might happen and the way I have solved issue.
This problems happens in the absence of war file. When I deployed
hawtio
to monitoring jboss which it needs
jolokia
so I just download and deployed manually the .war file into my jboss then problem has been solved.
I think you have to add WEB-INF/jboss-web.xml file in which you have set the context root
<jboss-web>
<context-root>contextroot</context-root>
</jboss-web>
Clean Server to solve this problem in many cases work..

NoClassDefFoundError accessing jackrabbit jar from servlet

I'm getting the above mentioned error when trying to access a repository
using jackrabbit-standalone-2.4.2.jar from a servlet. I didn't use the
jackrabbit war because I already have a thick client app working and I want
to reuse as much code as possible. I just assumed doing this was possible.
To test I created a small web application. Since I cannot attach a zip file
I will just copy the doPost() method below:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Repository repository = new TransientRepository(
"repository.xml", //embedded within the war
"path/to/home/dir");
Session session = null;
try {
session = repository.login();
System.out.println("root node identifier: " +
session.getRootNode().getIdentifier());
} catch (Exception e) {
e.printStackTrace();
} finally {
session.logout();
}
}
When I post to this servlet from an html form the exception has 2 parts:
java.lang.NoClassDefFoundError: javax/jcr/Repository
java.lang.ClassNotFoundException: javax.jcr.Repository
when I add jcr-2.0.jar in it then I get a different error:
java.lang.NoClassDefFoundError: org/apache/jackrabbit/core/TransientRepository
You originally got the ClassNotFoundException because that class wasn't in the classpath. You have fixed that. The NoClassDefFoundError means the class is in the classpath, but there was an problem initializing it. For details about this distinction, see also this question.
So the class TransientRepository is there, but most likely a class referenced by the TransientRepository isn't. That means most likely you didn't include other required jar files in the classpath. For a complete list of dependencies (required jar files), see the jackrabbit-standalone-2.4.2.jar, or see the Jackrabbit docs. It could also mean you have all jar files, but at least one of the jar files is the wrong version.
You originally got the ClassNotFoundException because that class wasn't in the classpath. You have fixed that.
The NoClassDefFoundError means the class is in the classpath, but there was an problem initializing it.

How to you get server information in HTTP response header for Apache Tomcat

We have n number of servers behind a load balancer. When a http request comes in, it is routed to one of the servers by round robin method. My question is, is there any way we can send the sever information in http response(The server to which the request is directed to) ?
If you have the information you want (IP address? some friendly name for the server?) you can easily just set the header using response.setHeader("Backend-Machine", "ServerName").
The real question is how to get that information. Most servers have multiple NICs which means you can't just pick one randomly and return the IP address (you're liable to get 127.0.0.1 which doesn't help anyone). If this is important to you, I'd recommend setting a system property on JVM launch that includes whatever string you think identifies the server. Then, write a Filter that just adds that string to every response.
Short answer on the sub-question "Where do you get the info".
TLDR;
say in: /opt/tomcat-<your_version>/lib$ execute:
java -cp catalina.jar org.apache.catalina.util.ServerInfo
You will get something like this, which is probably what you are looking for. I would pare it down to only what you need since the format essentially is just K/Vs, one per line, with colon as the delimiter.
Server version: Apache Tomcat/8.5.59
Server built: Oct 6 2020 16:57:18 UTC
Server number: 8.5.59.0
OS Name: Linux
OS Version: 5.4.0-72-generic
Architecture: amd64
JVM Version: 1.8.0_292-8u292-b10-0ubuntu1~20.04-b10
JVM Vendor: Private Build
I cannot believe this is so difficult. There should be just some Tomcat property that would allow it to tack the ServerInfo to the response, most likely in the "Server" response header.
Anyhow, since I have been digging for this, I have to say
Christopher Schultz
below is correct about the filter that needs to be added to the application. At least that would solve the problem for the given application. But how about the rest of the apps running on the same server (deployed WARs). Add a filter to each one? Sounds redundant. Here is a sample code snippet, though (you can see the original post here), many thanks to Maciej Walkowiak:
#Bean
public Filter myFilter() {
return new Filter() {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletResponse res = (HttpServletResponse) servletResponse;
res.addHeader("Server", "my very custom server");
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
};
}
And for the brave, here is the source of it. You can open this class in IntelliJ org.apache.catalina.util.ServerInfo, which will reveal:
Just grab the calls that you are interested in and populate what they return in you the Server header that you create in your Spring MVC filter.
And then the ServerInfo.properties, you can see just three of them:
Personally, I set the server header like so in application.properties of my Spring Boot project:
server.server-header="Servlet engine: [Apache Tomcat/9.0.58]"
This solves the issue on a server level and I don't need to touch the code for this included - tested in FireFox Developer Tools, network tab.

Resources