All Things Techie With Huge, Unstructured, Intuitive Leaps
Showing posts with label tomcat. Show all posts
Showing posts with label tomcat. Show all posts

Upgrading from Tomcat 7 to Tomcat 8



When we upgraded from Apache Tomcat 7.0.21 to 7.0.56, all that we did, was copy over every single file in the TOMCAT_HOME/conf directory into the new installation and everything worked perfectly. When I did the same thing upgrading to Tomcat 8.0.15, it blew apart. Tomcat would not even start. The exception in the logs was:

java.lang.classnotfoundexception org.apache.catalina.core.jasperlistener

The fix was to find the original server.xml and splice in our local stuff into it -- like the context and the appBase and the listening port.  Once we did that, it worked like a charm.

Hope this helps someone.

Issue with Cordova Framework and Apache-Tomcat



I have been having a major issue with Cordova framework for mobile app development.  To recap, when you press an HTML button, we have to transition from a web widget going to our server to an internal app screen that will handle a camera function.  The transition is made by having a fake url called "nextscreen" which is supposed to be trapped by a Javascript event listener in the app.  Instead of going to the scan screen, it goes to the domain index page.

The code used to go from the browser widget in the app looks like this:

              var browser = window.open(URL_ADDRESS + '?uId=' + User.getId() + '&tkn1=' + User.getToken1(),
                '_blank', 'location=no,toolbar=no');

              browser.addEventListener('loadstop', function (event) {
                if (event.url.match(NEXT_SCREEN_URL_PATTERN)) {
                  browser.close();
                  Util.go('/camerafunction');
                  $scope.$apply();
                } else if (event.url.match(BACK_URL_PATTERN)) {
                  browser.close();
                } else if (event.url.match(LOG_OUT_URL_PATTERN)) {
                  User.logoutPrompt(browser);
                } else if (event.url.match(FULL_SITE_URL_PATTERN)) {
                  browser.close();
                  Vehicle.clear();
                  Util.go('/camerafunction');
                  $scope.$apply();
                  window.open(FULL_SITE_ADDRESS + '?uId=' + User.getId() + '&tkn1=' + User.getToken1(), '_system');
                }
              });
            });

A Javascript event listener is attached to the browser widget and matches the URL pattern and it is supposed call /camerafunction.  Instead it goes to the welcome/index page in the domain -- in our case either the test server and/or the prod server.  There is a proviso.  We upgraded from Tomcat 7.0.21 to 7.0.56 and that seems to be the issue.  Whenever I regress the server back to 7.0.21, the app works.

I am intrigued that when the app works on 7.0.21, we get a little flash of the index page, and then the app goes to /camerafunction.  In 7.0.56, it is somehow trapped at the index page.  The reason that it is intriguing, is that there is nothing in the code to suggest that it should go to the domain welcome page, yet it does, and always has, albeit for just a second.

I ran extensive test to pinpoint the issue.  The match phrase for trapping is ".*nextcamera.*".  What I thought was happening was that the new server was being aggressive and recognizing the fake url.  If that was the case, then it should have thrown a 404 not found error.  I even tried that by putting garbage into the fake url, and it still took me to the domain welcome or index page.

Then I was wondering if perhaps an error on the index page interrupted the redirect from the Cordova web widget to the app /camerafunction screen, so I swapped out the index page for a single word -- a "Hello World" index page if you will. Nada.  So it doesn't throw 404 errors, and it doesn't hang up on the domain index page.

The next step was to upgrade the Tomcat to the latest series rev 7 server.  I downloaded and deployed Tomcat 7.0.57.  Nada. Same deal.  Then I wondered if perhaps some config were causing it.  So one by one, I went through and not only diffed server.xml, but context.xml, web.xml, noweb.xml and finally I got ticked off and substituted the entire $TOMCAT_HOME-7.0.21/conf to the latest.  Still buggy.  Regressing back to 7.0.21 again, and it worked.

I fired up the Mac Powerbook to see if the issue was the same with iOS.  It is.  I ran it in debug in XCode and didn't see anything - including in the console.

I downloaded Google Chrome Canary to do a device inspection, but the only Android device that I have is an older Samsung Galaxy, and even enabling it for USB debugging, Chrome couldn't find the device.

There is no way that we can go back to Tomcat 7.0.21 because of security holes.  What I find totally weird, is why and how the index page comes up with the event listener URL intercept. That is totally baffling to me.  There is nothing in the code to even suggest that this should happen. Since this behavior happens in the non-buggy, working server version and the later non-working version, something has to be happening in the app, otherwise we would be throwing 404 errors. The JRE (Java Runtime Environment) is the same, and even if it wasn't, an event listener should behave the same way regardless of the JRE.

I still haven't solved this one. If you have run into this before, and have solved it, please leave a comment. Educated guesses welcome.

Using the Android Simulator Webview, with Localhost and Apache Tomcat

Okay, let's suppose that you are developing an Android app with server support.  Let's suppose that you are using the server to securely access a database and you are using JSPs to do it, since Android is Java and you know Java.  So using Tomcat (what else) to serve up the JSPs, you want to do the development running Tomcat on your computer.  When you fire up your simulator to test the webview app and try to access the web url using http://localhost:8080, nothing happens.

Why?  Because the simulator is using localhost.  127.0.0.1 doesn't work either.  The simulator acts as a router, so if you want to access http://localhost:8080/index.jsp the way that you would do it in a browser, the URL host in the activity has to appear as 10.0.2.2 as the IP address.  So in the above example, you would use http://10.0.2.2:8080/index.jsp.

If you are like me, you have a separate Eclipse for Android development.  You can either start Tomcat using the service control panel, or you can invoke both the Android Eclipse SDK and the JSP Eclipse SDK.  I don't try to combine the two with two separate projects just for simplicity sake.

And that brings us to last item of integrating webview with an Android app.  Suppose you have a webview page and you want to trigger an activity with a URL instead of going to another JSP.  Easy peasy.

In your activity where your webview is, find the following bit of code:

WebView webview = (WebView) findViewById(R.id.webview);
        webview.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });


This is a standard bit of code for displaying a URL from a web server in webview.  To make a url do an activity, you modify it easily.  The first thing that you do, is that you signal an activity in the URL.  One way is to construct the url like:   <a href="app://signal_activity">

Then modify the above method to catch that string:

 WebView webview = (WebView) findViewById(R.id.webview);
       webview.setWebViewClient(new WebViewClient() {
           @Override
           public boolean shouldOverrideUrlLoading(WebView view, String url) {
              // view.loadUrl(url);
            if (url.contains("app://signal_activity")){
                    
                   //trigger an Android action...,

               return true;
            }
            return super.shouldOverrideUrlLoading(view, url); 
           }
       });

There you go -- everything that you need to know to (1) use your local machine as the web server (2) use Tomcat to serve up the web stuff for the Android web view (3) use your Android simulator with your local machine and (4) integrate web pages with Android activities.

Hope this helps.

PHP on Tomcat with JSPs




First of all, in spite of the fact that the world runs on LAMPS (Linux, Apache, MySQL, PHP, SQL), I really dislike PHP or Python.  They are sort of pseudo-Object Oriented and do not have the power of J2EE where one can integrate pure Java classes with JSPs.  My preferred approach is LAMJS where J is JSP or Java.  Our webserver is Apache Tomcat.

At any rate, we have a rang-dang-doo enterprise app written with Java, JSP, ServerFaces, and all of the good stuff.  Our business requirements say that we have to have a blog and a newsletter and a marketing side to our enterprise app.  We only have so many developers and we believe in the AGILE approach with continuous iteration and working software.  So to put the marketing side in place, we decided not to re-invent the wheel.  Wordpress has templates galore and all of the features that we need.  Wordpress is written in PHP and uses PHP, so we have to make Tomcat play with JSPs and PHP.  It was a hair-pulling experience.

The first thought was to use JavaBridge and JavaBridge.jar.  We kept getting this stack trace:



Fatal Error: Failed to start PHP ["php-cgi", "-v"], reason: java.io.IOException: Cannot run program ""php-cgi"" (in directory "C:\Users\Delon"): CreateProcess error=2, The system cannot find the file specified
Could not start FCGI server: java.io.IOException: PHP not found. Please install php-cgi. PHP test command was: [php-cgi, -v] 

php.java.bridge.http.FCGIConnectException: Could not connect to server
at php.java.bridge.http.NPChannelFactory.test(NPChannelFactory.java:64)
at php.java.bridge.http.FCGIConnectionPool.<init>(FCGIConnectionPool.java:175)
at php.java.bridge.http.FCGIConnectionPool.<init>(FCGIConnectionPool.java:189)
at php.java.servlet.ContextLoaderListener.createConnectionPool(ContextLoaderListener.java:541)
at php.java.servlet.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:185)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException: File \\.\pipe\C:\Program Files\Apache Software Foundation\Tomcat 7.0\temp\JavaBridge3030620009245189355.socket not writable
at php.java.bridge.http.FCGIConnectException.<init>(FCGIConnectException.java:37)
... 15 more
Caused by: java.io.IOException: PHP not found. Please install php-cgi. PHP test command was: [php-cgi, -v] 
at php.java.bridge.Util$Process.start(Util.java:1145)
at php.java.servlet.fastcgi.FCGIProcess.start(FCGIProcess.java:68)
at php.java.bridge.http.NPChannelFactory.doBind(NPChannelFactory.java:94)
at php.java.bridge.http.FCGIConnectionFactory.runFcgi(FCGIConnectionFactory.java:88)
at php.java.bridge.http.FCGIConnectionFactory$1.run(FCGIConnectionFactory.java:109)


Obviously we hadn't configured Tomcat to find the PHP executables which were supposed to be in the .war file.  We tried various things like trying to install PHP on Windows (our dev machines are Windows, but our production and test servers are Linux), all to no avail.  We found plenty of instructions on how to show Apache how to find the PHP executables, but none for Tomcat.

I was really looking for a plug and play solution, and I found it with Caucho and their Quercus war file.  I simply downloaded the war file, and took a copy of it.  I changed the copy's .war extension to a .zip extension and unzipped it.  I took the resultant folder and dropped it into our webapps folder where Tomcat could find it and it worked first time.  Someone ought to preserve their blood for posterity.  You too can make PHP play with Tomcat by downloading the war file from here:  http://quercus.caucho.com/

 Thank you Caucho and Quercus where ever you are.

java.lang.UnsupportedClassVersionError: Unsupported major.minor version 51.0



One of my programming guys was getting this error:

java.lang.UnsupportedClassVersionError:  Unsupported major.minor version 51.0

and Tomcat failed to start.

The message from the tomcat logs was:

SEVERE: Catalina.start: 
org.apache.catalina.LifecycleException: Failed to start component [StandardServer[8005]]

The fix was simple.  He was compiling at JRE version 1.7 and the JRE on the server was 1.6.  This was easily fixed in Eclipse under Project Properties > Java Compiler.

Hope this helps someone.

Setting Up JNDI JDBC MySQL Connection Pool in Tomcat

So it was time to set up a connection pool for our high concurrency application.  It seemed like an easy thing to do.  I went to avajava.com followed one of their instruction tutorials, and burned a whole afternoon debugging.  Tomcat 7 has connection pooling built in, so I figured it would be a walk in the park.  Man, I got the following list of errors:



  • org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to org.apache.tomcat.jdbc.pool.DataSource
  • name is not bound in this context. unable to find 
  • java.lang.ClassNotFoundException: org.apache.tomcat.jdbc.pool DataSourceFactor
  • java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to org.apache.tomcat.jdbc.pool.DataSource
  • java.lang.ClassNotFoundException: org.apache.tomcat.jdbc.pool DataSourceFactory
After wasting a whole bunch of time, I finally got it to bind to the database resource, but I had an error with the login stored procedure.  It was this one:

  • mysql - java.sql.SQLException: Parameter number 3 is not an OUT parameter

I knew that I was getting some sort of binding but not a good connection.  Not knowing what I didn't know, I decided to do a debug on my connection called conn:

                       System.out.println(conn.toString());
System.out.println(conn.getCatalog());
System.out.println(conn.getAutoCommit());
System.out.println(conn.getMetaData().allTablesAreSelectable());
System.out.println(conn.getMetaData().getDriverName());
System.out.println(conn.getMetaData().getMaxConnections());
System.out.println(conn.getMetaData().supportsStoredFunctionsUsingCallSyntax());
System.out.println(conn.getMetaData().supportsStoredProcedures());
System.out.println(conn.getMetaData().allProceduresAreCallable());


It was quite an interesting transcript.  It told me that getMaxConnections() was zero, that allTablesAreSelectable was false, and allProceduresAreCallable() was false.  I spent a lot of time chasing down this dead end rabbit hole.

Finally I went to the expert:

http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency

I followed the instructions implicitly and voila -- every thing works:

Simple Connection Pool for MySQL

<Resource type="javax.sql.DataSource"
            name="jdbc/TestDB"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/mysql"
            username="mysql_user"
            password="mypassword123"
/>
The first thing we notice is the factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" attribute.
When Tomcat reads the type="javax.sql.DataSource" it will automatically configure its repackaged DBCP, unless you specify a different factory. The factory object is what creates and configures the connection pool itself.
There are two ways to configure Resource elements in Apache Tomcat.
Configure a global connection pool
File: conf/server.xml
<GlobalNamingResources>
  <Resource type="javax.sql.DataSource"
            name="jdbc/TestDB"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/mysql"
            username="mysql_user"
            password="mypassword123"
/>
 </GlobalNamingResources>
You then create a ResourceLink element to make the pool available to the web applications. If you want the pool available to all applications under the same name, the easiest way is to edit the File: conf/context.xml
<Context>
  <ResourceLink type="javax.sql.DataSource"
                name="jdbc/LocalTestDB"
                global="jdbc/TestDB"
/>
 <Context>
Note, that if you don't want a global pool, move the Resource element from server.xml into your context.xml file for the web application.
And to retrieve a connection from this configuration, the simple Java code looks like
Context initContext = new
 InitialContext();
   Context envContext  = (Context)initContext.lookup("java:/comp/env");
   DataSource datasource = (DataSource)envContext.lookup("jdbc/LocalTestDB");
   Connection con = datasource.getConnection();

Mister TomcatExpert is really an expert.



Domain Name Works but www domain name not resolving

Tomcat again. I wasted a lot of time on this. I went to Godaddy and changed my domain name and the IP address associated with it. After that, I went to my Apache Tomcat server and changed the hostname to mydomain.com.

Then I went back and tried to access the website. It would work. It would work without the www, just the http://mydomain.com but not with http://www.mydomain.com. Couldn't figure it out. I thought it was a Godaddy issue. It wasn't.

In desperation, I went to the Tomcat server.xml and called the host "www.mydomain.com" with an alias. Everything works. Thought that I would pass it along to save you some time.

Tomcat Startup Problem

I had a strange issue. I used Apache Tomcat with Eclipse, and all of a sudden, Tomcat wouldn't start. It threw the exception:

java.lang.ClassNotFoundException: org.apache.catalina.loader.DevLoader

This was strange.

There are two fixes. DevLoader is not provided with Tomcat, so you can put the DevLoader jar in your classpath.

Or:

You can navigate to ~tomcat_home/conf/Catalina/localhost/. In that directory, you will find a file with the name of your project and the .xml extension. It is a context.xml file. Open the file with a file editor.
You will find this line:


Remove the line and Tomcat will start again.