简体   繁体   中英

Call method in one webapp from another in a Tomcat instance

The problem: I have a Java webapp running in a Tomcat instance, and a second JSP webapp, JReport, in the same Tomcat instance. I need to use JReport to generate a report, and then send the results to the primary webapp as securely as possible/reasonable.

I'd like to use encrypted DB IDs that depend on a Tomcat session, but I'd settle for unencrypted IDs or temporary tokens. Some quick research (read: Googling) has told me that this should be possible with Tomcat cross-context.

The possible solution: This webpage gives some brief instructions for calling a method between two webapps using the Spring framework. Neither my webapp nor JReport uses Spring that I'm aware of, so I'm having trouble figuring out how to apply the code sample to my code.

The code: This code is adapted from the example on the page linked above. There are two places where I don't know what parameters to put into function calls:

private void sendPdf(HttpServletRequest request, String custCode, int reportId, int documentId, byte[] data) {
    ServletContext srcServletContext = request.getSession().getServletContext();

    // Where does this parameter come from???
    ServletContext targetServletContext = srcServletContext.getContext("/Bar");

    //save the class loader which loaded the 'Foo' application in a variable
    ClassLoader currentClassLoader = Thread.currentThread().
    getContextClassLoader();

    try {
        // What attribute name to put here???
        Object object = targetServletContext.getAttribute
        ("org.springframework.web.servlet.FrameworkServlet.CONTEXT.bar");

        // Get the class loader for Yawl and set it as the current class loader
        ClassLoader targetServiceClassLoader = object.getClass().getClassLoader();
        Thread.currentThread().setContextClassLoader(targetServiceClassLoader);

        // Get the ReportSigner class and its static method
        Class<?> reportSignerClass = (Class<?>) targetServiceClassLoader.loadClass("com.procentive.yawl.logic.report.ReportSigner");
        Method targetMethod = reportSignerClass.getMethod("addReportPdf", String.class, Integer.class, Integer.class, byte[].class);

        // Invoke the static method on ReportSigner
        targetMethod.invoke(null, custCode, reportId, documentId, data);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // Revert to original class loader
        Thread.currentThread().setContextClassLoader(currentClassLoader);
    }
}

This is my app's context.xml (also adapted from the same page):

<?xml version="1.0" encoding="UTF-8"?>
<context cookies="false" override="true" crossContext="true">
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
</context>

The question: What's the context name that I put into getContext() on line 5? What's the attribute name that I put into getAttribute() on line 14? Is this the right way to go about inter-webapp communication? Or would it be better/easier/more secure to do something else entirely?

Update

After some difficulties getting JReport to run the new code, I'm finally able to test this. I followed the example of this answer from another question, and am trying to use a servlet and RequestDispatcher.

Relevant code (yawl_server is the app getting called; jreport is the app doing the calling):

Tomcat server => server.xml (possibly rendering yawl_server => context.xml redundant?):

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
    <Context docBase="yawl_server" path="/yawl_server" crossContext="true" reloadable="true" source="org.eclipse.jst.jee.server:yawl_server"/>
</Host>

jreport => Servlet:

ServletContext context = getServletContext().getContext("/yawl_server");
RequestDispatcher rd = context.getRequestDispatcher("/reportsign");
rd.forward(request, response);

When I reach this code, context is always null, despite the two apps (supposedly?) running in the same virtual host and the argument to getContext() matching the path attribute of the context. What am I doing wrong?

I had a problem like this, and I found a solution for that You can pass data by many ways:

  1. By making http request from your app:

    URLConnection conn = new URL("your other web app servlet url").openConnection(); // pass data using conn. Then on other side you can have a servlet that will receive these calls.

  2. By using JMS for asynchronous communication.
  3. By using Webservice (SOAP or REST)
  4. By using RMI
  5. By sharing database between the apps. So one writes to a table and the other reads from that table By sharing file system file(s)...one writes to a file the other reads from a file.
  6. Using Socket Connections .

The solution I went with was forwarding the request to a new servlet in my app, after configuring my server.xml with both contexts configured with crosscontext="true".

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
    <Context docBase="yawl_server" path="/yawl_server" crossContext="true" reloadable="true" source="org.eclipse.jst.jee.server:yawl_server"/>
    <Context path="/jreport" crossContext="true"></Context>
</Host>

When forwarding the request, I wanted to add another parameter to it, so I had to do add that as a GET parameter:

ServletContext context = getServletContext().getContext("/yawl_server");
RequestDispatcher rd = context.getRequestDispatcher("/reportsign?reportFilename=" + filename);
rd.forward(request, response);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM