Implementing Tomcat Custom Valve - tomcat6

I am trying to implement a custom valve in Tomcat, say MyValve which extends BaseValve.
I created a jar of the project and added it into the Tomcat\lib folder.
The next step is of configuring the server.xml or context.xml.
I tried both.
But my valve class is not getting detected.
Could someone please let me know the steps to create a valve and use it.
Thanks

The question is on steps required to create a custom valve and use it. So let me explain it step by step for someone else also to take advantage of it. For my example, I will use a Java Maven Project. (Git Project)
Step 1: Open a new or existing maven project (you can also clone from the above repo).
Step 2: Add the following dependency to the pom.xml file.
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>7.0.85</version>
<scope>provided</scope>
</dependency>
Step 3: Under src/main/java path, create a package and create a new Java Class: TomcatValve.java (could be any name). Extend this class by ValueBase class.
Step 4: With this, you will have to implement its invoke method. The entire class would look something similar to this:
import java.io.IOException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
/**
* #author Keet Sugathadasa
*/
public class TomcatValve extends ValveBase {
private static final Logger logger = Logger.getLogger(TomcatValve.class.getName());
public void invoke(Request request, Response response) throws IOException, ServletException {
HttpServletRequest httpServletRequest = request.getRequest();
Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
logger.info("Receiving request");
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
logger.log(Level.INFO, "Header --> {0} Value --> {1}", new Object[]{header, httpServletRequest.getHeader(header)});
}
getNext().invoke(request, response);
}
}
Step 5: Open a terminal, and run mvn install. Now in the target/ folder, there jar should have been built.
Step 6: Copy this jar to ${TOMCAT_HOME}/lib or ${CATALINA_HOME}/lib folder. This is usually in /usr/local/apache-tomcat9/lib.
Step 7: Go to ${TOMCAT_HOME}/conf or ${CATALINA_HOME}/conf folder and add the following line to server.xml:
Classname: TomcatValve
PackageName: com.keetmalin.tomcat
<Valve className="com.keetmalin.tomcat.TomcatValve"/>
Step 9: Go to ${TOMCAT_HOME}/bin or ${CATALINA_HOME}/bin folder and run the following command in a terminal:
./catalina.sh run
Step 10: Next, your Tomcat server will start. Open a browser and go to http://localhost:8080/ and go back to the terminal. You will see that the logs are being printed. Now instead of printing logs, you can do anything you wish. Hope it helps!

What version of Tomcat are you running? The CATALINA_HOME\lib is the correct directory for Tomcat v6.x (and v7, I believe). If your valve is not getting picked up it could be that you are not editing the server.xml or context.xml files in your CATALINA_BASE directory. Are you using Eclipse IDE or something similar? If so, check your Tomcat server settings because it copies XML files from CATALINA_HOME (installation) to CATALINA_BASE (configured instance) directory. This problem tripped me up for a while.

I found that I had created a jar which contained the java file, instead of the class file using netbeans.
The solution that worked for me was to create a jar with the correct directory structure for the package (MyValve.jar\org\apache\catalina\connector\) and stick the class file in that directory. I put the jar in the same location (CATALINA_HOME\lib).
I added an entry to the server.xml file inside the <Host> section like this:
<Valve className="org.apache.catalina.connector.MyValve"
classField="value">

Related

Querying MS Sql Server from a Jenkins Pipeline

I've been using Jenkins (2.289.3) in a docker container (https://hub.docker.com/r/jenkins/jenkins). The next update to Jenkins 2.312 migrates the docker container from Java 8 to Java 11.
I have some pipelines that use the sourceforge jdbc driver to query SQL server (http://jtds.sourceforge.net/)
Example:
import java.sql.DriverManager
import groovy.sql.Sql
con = DriverManager.getConnection('jdbc:jtds:sqlserver://servername', 'user', 'password');
stmt = con.createStatement();
To make this work, in the Docker container on Java 8 I ran this on the docker container
cp jtds-1.3.1.jar ${JAVA_HOME}/jre/lib/ext
Which loads the jar for use inside Jenkins. This method no longer exists with Java 11.
It seems pipelines have added the #Grab syntax, eg
#Grab(group='net.sourceforge.jtds', module='jtds', version='1.3.1')
If I add this to my pipline, I can see the Jars are downloaded in /var/jenkins_home/.groovy/grapes/ but it doesn't seem to actually load the jar
java.lang.ClassNotFoundException: net.sourceforge.jtds.jdbc.Driver
or
java.sql.SQLException: No suitable driver found for jdbc:jtds:sqlserver://servername
depending on which commands I run. Either way, it appears to be due to the jar not being loaded.
All the groovy examples use
#GrabConfig(systemClassLoader=true)
But this appears to not be supported in pipelines.
I've considered using a command line client, but I need to parse the results of queries and I haven't seen a tool that works well for this (ie, one that would load results into a json file or similar)
I've also tried setting the -classpath argument in the docker container, eg
ENV JAVA_OPTS=-classpath /var/jenkins_home/test/jtds-1.3.1.jar
Running ps in the docker container, I can see that the java process runs with the classpath command line option specified, but it doesn't seem to actually load the jar for use.
I'm a bit lost on how to get this working, can anyone help? Thanks.
Well, I've found a workaround. It doesn't seem ideal, but it does work
The original code
import java.sql.DriverManager
import groovy.sql.Sql
con = DriverManager.getConnection('jdbc:jtds:sqlserver://servername', 'user', 'password');
stmt = con.createStatement();
Assuming we have the jar saved in /var/jenkins_home/test/jtds-1.3.1.jar it can be updated to:
import java.sql.DriverManager
import groovy.sql.Sql
def classLoader = this.class.classLoader
while (classLoader.parent) {
classLoader = classLoader.parent
if(classLoader.getClass() == java.net.URLClassLoader)
{
// load our jar into the urlclassloader
classLoader.addURL(new File("/var/jenkins_home/test/jtds-1.3.1.jar").toURI().toURL())
break;
}
}
// register the class
Class.forName("net.sourceforge.jtds.jdbc.Driver")
con = DriverManager.getConnection('jdbc:jtds:sqlserver://servername', 'user', 'password');
stmt = con.createStatement();
Once this code has been run once, the jar seems to be accessible globally (even in other pipelines that don't load the jar).
Based on this, it seems like a good way to handle this is on the Jenkins initialization, rather than in the script at all. I created /var/jenkins_home/init.groovy with these contents:
def classLoader = this.class.classLoader
while (classLoader.parent) {
classLoader = classLoader.parent
if(classLoader.getClass() == java.net.URLClassLoader)
{
classLoader.addURL(new File("/var/jenkins_home/jars/jtds-1.3.1.jar").toURI().toURL())
break;
}
}
Class.forName("net.sourceforge.jtds.jdbc.Driver")
And after that, the scripts seem to behave similar to how I think it should work with the Jar in the classpath.

Flink webui when running from IDE

I am trying to see my job in the web ui.
I use createLocalEnvironmentWithWebUI, code is running well in IDE, but impossible to see my job in http://localhost:8081/#/overview
val conf: Configuration = new Configuration()
import org.apache.flink.configuration.ConfigConstants
conf.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true)
val env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf)
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
val rides = env.addSource(
new TaxiRideSource("nycTaxiRides.gz", 1,100))//60, 600))
val filteredRides = rides
.filter(r => GeoUtils.isInNYC(r.startLon, r.startLat) && GeoUtils.isInNYC(r.endLon, r.endLat))
.map(r => (r.passengerCnt, 1))
.keyBy(_._1)
.window(TumblingTimeWindows.of(Time.seconds(5)))
.sum(1)
.map(r => (r._1.toString+"test", r._2))
filteredRides.print()
env.execute("Taxi Ride Cleansing")
Did I need to setup something else?
I was able to start the Flink webui from IntelliJ by adding flink-runtime-web to the dependencies for my project. I did this by adding this to my pom.xml file:
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-runtime-web_2.11</artifactId>
<version>${flink.version}</version>
</dependency>
You also then need to create a local execution environment that includes the WebUI:
Configuration conf = new Configuration();
env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
As of Flink version 1.5.0 adding the dependency mentioned before and using the following piece of code to start the StreamEnvironment worked for me:
Configuration config = new Configuration();
config.setBoolean(ConfigConstants.LOCAL_START_WEBSERVER, true);
StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(config);
While the processing is running, the web UI is available under http://localhost:8081
Yes, if you want to use WebUI Dashboard, then you need to create an executable jar and then submit this jar to Flink dashboard. I will explain you this step by step
Step 1: Creating the jar from IDE code
you may need to change your execution environment to
StreamExecutionEnvironment envrionment =
StreamExecutionEnvironment.getExecutionEnvironment();
In case you have multiple jars, then set the main class in
Main-Class: variable of Manifest.mf file
Then create a jar using build artifacts in your IDE
Step 2: Start flink-local cluster which will show you dashboard.
I will assume that you have not downloaded the Flink binary, you can
easily download it here, if you have Macintosh, I will suggest you to
use brew install apache-flink which will download the latest stable
release which is 1.3.2 currently
Ok, now you have to go to path where flink is installed and start
local cluster
Step# 3 : submitting the job
submit jar via submit new job option and then run it

ClassNotFoundException with Netbeans and H2 Database

So I followed the tutorial on the H2 Documentation page and used the "Connecting to a Database using JDBC" method of connecting to the database. I First added the h2-*.jar file to the Lib Folder (through Netbeans) and used the following to make the connection to my database I previously created.
Class.forName("org.h2.Driver");
connection = DriverManager.getConnection("jdbc:h2:~/" + DatabaseName);
This turned out to work in the IDE environment, however when I attempted to run the application directly from the jar executable I get the following error:
java.lang.ClassNotFoundException: org.h2.Driver ...
this error occurs at the Class.forName() class loader. So I did a little looking around and found that this was a prominent problem. One solution people use was to extract the class Loader from the current Thread as so:
Thread t = Thread.currentThread();
ClassLoader cl = t.getContextClassLoader();
cl.getClass().getClassLoader();
Class toRun = cl.loadClass("org.h2.Driver");
Unfortunately this seems to still result in the same error, so i'm wondering what i'm doing wrong. Should I be doing something to make sure the Driver is in the class path? I have no I idea how if that's the case.
Thanks!
You need to add the h2-*.jar file to the classpath when running the application, for example using
java -cp h2*.jar -jar yourApp.jar

opening a file inside the jar

I have an ant script which does lots of stuff but I have been asked to provide jar so it can be run as an app.
I have managed to write the java code to invoke ants programatically but I am having the problem to refrence the build file from the code.
File buildFile = new File(BUILD_FILE);
where BUIlD_File is my build.xml (exists in the main directory).
When I export my proj as Runnable jar it throws an exception (File not found build.xml)
Even if I add the build.xml file into jar still it moans though if I put the build.xml file in the same folder where the jar is then it works fine. (But i dont wanna do this)
Can aynone guide me how can I make sure when I export as jar the build.xml file is added in jar and how can I refrence that file(inside jar) in my code.
Any Object running in the JVM can fetch an InputStream for any resource/file within the JAR as follows:
InputStream is = this.getClass().getResourceAsStream("yourpackage/yourfile.xml");
In your case, it sounds like build.xml isn't in a package so you should be able to use:
InputStream is = this.getClass().getResourceAsStream("build.xml");

gwt file permission

I have a little GWT/AppEngine Project which uses RPC. Basically I need to get some data from a XML file that resides on the server. But when I use the RPC to read the file in my server-package I am getting a AccessControlException (access denied). Any ideas what the problem is?
//JAXB powered XML Parser
public PoiList readXML() {
try {
unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setEventHandler(new XMLValidEventHandler());
db = (PoiList) unmarshaller.unmarshal(new File("src/com/sem/server/source.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
return db;
}
java.security.AccessControlException: access denied (java.io.FilePermission \WEB-INF\classes\com\sem\server read)
cheers hoax
I think the problem is that you're trying to read a file that is not located in your working directory. The guidlines for structuring your code in gwt apps are as follows
Under the main project directory
create the following directories:
src folder - contains production Java source
war folder - your web app; contains static resources as well as compiled output
test folder - (optional) JUnit test code would go here
Try moving the file to the war directory (for example /war/resources/myFile.xml) and then open it by
File myFile = new File(System.getProperty("user.dir") + "/resources/myFile.xml");
Usually, when you load a resource that is located in your classpath, you should't use java.io.File. Why? Because it's very much possible, that there is no real file - the classes are often packaged as a .jar file, or even loaded in a completely different way (very likely in the case of AppEngine, though I don't know the details.)
So, if you want to load it directly from your classpath, you can use:
ClassLoader classLoader =
getClass().getClassLoader(); // Or some other way to
// get the correct ClassLoader
InputStream is = classloader.getResourceAsStream("/com/sem/server/source.xml");
Then you can use the input stream in your unmarshaller.

Resources