Custom Maven plugin for encryption - java

I'm translating an Ant script to Maven 2 and I have this problem: the Ant script use a pretty simple java class to encrypt files this way:
<target name="encrypt">
<java classname="DESEncrypter">
<classpath>
<pathelement path="...classpath for this thing..." />
</classpath>
<arg line="fileToEncrypt.properties fileEncrypted.properties" />
</java>
</target>
This DESEncrypter is a compiled class which source doesn't belong to the project I am converting but is used similarly in other projects. Probably I have to create a maven plugin for this to reuse, but I don't want to do it now. My question is: in which directory do i put the DESEncrypter class and how do i invoke it? Using the exec:java plugin, may be? I don't think the encrypter belong to src, test or resources directories.
Obviously, I don't want to include the encrypter class in the final product, just the encrypted files.

My question is: in which directory do i put the DESEncrypter class and how do i invoke it? Using the exec:java plugin, may be? I don't think the encrypter belong to src, test or resources directories.
A very straightforward solution would be to use the Maven AntRun Plugin. Regarding the location of your encrypter, you could either:
put it in a separate module that you could declare as dependency OF the plugin (see this example)
keep it in the current module, in the source tree, and configure the Maven JAR Plugin to exclude it using excludes.

The third obvious answer (apart from exec:java and antrun) is GMaven, which lets you execute Groovy code either from an external class or inline from your pom. So if you only need a one-liner, embedding it in your pom is a quick and easy way to implement things (otherwise you should use an external script). BTW: if you don't know groovy: it's basically java with some additional syntax sugaring.
Here's a sample configuration (of course you have to replace the artifact and class you use):
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>your.library.com</groupId>
<artifactId>your-library</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>process-classes</phase>
<!-- Or any other phase -->
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source><![CDATA[
import com.encryption.*;
new Encrypter().encrypt(
new File(project.build.outputDirectory,
'fileToEncrypt.properties'),
new File(project.build.outputDirectory,
'encryptedFile.properties')
)
]]></source>
</configuration>
</execution>
</executions>
</plugin>
(By making the encryption artifact a plugin dependency, you keep it out of your deployed dependencies, but this holds true for antrun and exec:java also)

You might want to just use the AntRun plugin, it should let you accomplish anything from Ant with a minimum amount of fuss.
You would need a dependency on the class/jar you were using, but by giving it a scope of test, or provided it won't package it in your final product.

Related

Can't import proto file from java file Intellij id

I'm trying to import a proto file from a java file in IntelliJ IDEA.
I have a file called A.proto and a file called B.java. I try to import a class Info from the A.proto file in the B.java file like this:
import A.Info;
However, IntelliJ IDEA doesn't look to support proto files and says my class doesn't exist. I installed both plugins Protobuf Support and Protocol Buffer Editor. But it still doesn't work. Any idea?
Problem
IntelliJ recognizes protocol buffer files, but they are not Java, so the Java Compiler doesn't know what to do with them.
Solution with Maven
You can compile those protocol buffers to Java files, which is the step you are currently missing. The best way I know is to use a Maven plugin to do this.
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.11.4</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocVersion>3.0.0</protocVersion> <!-- 2.4.1, 2.5.0, 2.6.1, 3.0.0 -->
<includeDirectories>
<include>src/main/resources/protobuf</include>
</includeDirectories>
<inputDirectories>
<include>src/main/resources/protobuf/</include>
</inputDirectories>
</configuration>
</execution>
</executions>
</plugin>
And dependency for the Protocol Buffer classes:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.4</version>
</dependency>
With this plugin, Intellij will find the created Java classes, after having initially created the sources. This way, only your Protocol Buffer files need to be in Source Control. You let the plugin take care of the compilation to Java.
After creation of the Java classes, you can use them in the rest of your code. You can even view the generated Java classes in the target/generated-sources folder in your Maven Project.
Here's what the mapping between Protocol Buffers and Java looks like:
DistanceWalked.proto
package example;
message DistanceWalked {
string userId = 1;
double distance = 2;
}
DistanceWalkedOuterClass.DistanceWalked.java (generated)
package example;
public class DistanceWalked {
//properties This class isn't pretty...
}
(Full code example with protocol buffers and Maven plugin can be found here: https://github.com/TomCools/protocol-buffers-example)
Link to plugin source: https://github.com/os72/protoc-jar-maven-plugin
Solution without Maven
Without Maven, you have to download the command-line compiler. Documentation on that can be found here: https://developers.google.com/protocol-buffers/docs/javatutorial#compiling-your-protocol-buffers
The proto file is just the description of the message format. It does not contain code that can be interpreted directly in a java context.
The idea of the proto file is to provide a generic, language agnostic specification of the message format.
Based on the proto file, you can generate the corresponding java code. This code can then be used and imported in your java project.
Have a look here on how to generate code from a proto file: https://developers.google.com/protocol-buffers/docs/javatutorial#compiling-your-protocol-buffers
Incase anyone is still stuck -
I found that specifying the path to Intellij fixes the problem:
Preferences -> Languages and Frameworks -> Protocol Buffer -> Uncheck "Configure automatically"
And then add the path to the file.
It should be good for xolstice or os72!

How to get name of Maven dependency JAR (not full path) as a pom.xml variable

It looks like it is possible to get the path/to/a/dependency.jar as an expandable variable within a Maven pom.xml: see Can I use the path to a Maven dependency as a property? You can expand, e.g., an expression into a string like /home/pascal/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar.
What I want instead of the full path to the dependency JAR within my local Maven repository is just the bare name of the JAR, for example junit-3.8.1.jar.
So for example, within my pom.xml, I would like to be able to use a value like ${maven.dependency.junit.junit.jar.name} to expand to junit-3.8.1.jar.
Can I do this, and how?
You can use the maven-antrun-plugin to get the file name of a dependency. Ant has a <basename> task which extracts the file name from a path. As described in Can I use the path to a Maven dependency as a property? the full path name of a dependency is available in ant as ${maven.dependency.groupid.artifactid.type.path}. This enables us to extract the file name with the ant task like this:
<basename file="${maven.dependency.groupid.artifactid.type.path}" property="dependencyFileName" />
This stores the file name in a property named dependencyFileName.
In order to make this property availbable in the pom, the exportAntProperties configuration option of the maven-antrun-plugin needs to be enabled. This option is only available as of version 1.8 of the plugin.
This example shows the plugin configuration for retrieving the artifact file name of the junit dependency:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>initialize</phase>
<configuration>
<exportAntProperties>true</exportAntProperties>
<tasks>
<basename file="${maven.dependency.junit.junit.jar.path}"
property="junitArtifactFile"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
No, I'm sorry to say that it isn't possible. So, you have two options before you.
1) modify the maven source code and contribute the modification.
2) write your own plug-in.
I recommend the second option. Writing plug-ins is not that hard. As a philosophical principal, select a frequently-used plug-in which has functionality close to what you want to accomplish. Read and understand the code, and then modify it to do what you desire.
So for your example, you might look at the filter plugin. There's also some interesting syntax going on in the Ant plugin. It allows you to name dependencies and get those jar filenames into the embedded Ant script.
Good luck. :-)
As a more practical alternative, you might just break down and manually code the property value with the exact version number you're using. You're not going to switch the version number that often, right? And this is only one jar you're dealing with, right?

Using jaxws-maven-plugin with -clientjar option

I'm using jaxws-maven-plugin to execute wsimport for a web service consumer app. I'm using the -clientjar option on wsimport which was introduced with JAX-WS 2.2.2 RI in 2010. I do this because I want to bundle the WSDL within the jar.
I don't have a problem crafting the pom. For plugin configuration I do something like:
<configuration>
...
<args>
<arg>-clientjar</arg>
<arg>bundled-wsdl.jar</arg>
</args>
</configuration>
When I execute a build my created jar, lets call it myapp.jar, has file bundled-wsdl.jar within it. Inside the bundled-wsdl.jar's META-INF directory I find the wsdl and xsd just as I like them. I'm also quite happy with the generated java code that come as a result of using the -clientjar option. So far so good.
But this stuff should be in myapp.jar's META-INF, right?
The fact that it sits within bundled-wsdl.jar's META-INF doesn't help me a lot.
The funny thing is that I do in fact get a wsdl file in myapp.jar's META-INF which makes the application actually work. How it gets there I don't know. Also the xsd file isn't there, only in bundled-wsdl.jar's META-INF.
The basic question is how to correctly use wsimport -clientjar option in a Maven project ?
Java 1.7.0_45.
The -clientjar option is really poorly documented, IMHO.
Here's how I believe it works:
When the -clientjar <jarfile> option is used three things are happening:
You'll get a <jarfile> generated in the directory pointed to by
the -d argument to the wsimport tool. This will contain within
it both WSDL and any relevant XSD files as well. This little bundle will not be used for anything at all. If you want to make use of it it would be entirely up to you. But before you do see (2) below. I'm not sure what to use this jarfile for other than as a form of documentation.
You'll get a copy of the WSDL put into a file called
META-INF/wsdl/<svcname>.wsdl. The generated classes will use this
file in the no-arg proxy constructor. So this is what will actually
be used if you request a bundled WSDL file with the -clientjar
option.
The generated code will change so that wsdlLocation, if you are using the default no-arg constructor on the #WebServiceClient class, will be that of the bundled WSDL (from (2)), rather than the remote WSDL. Indeed if you use -wsdllocation on your command line together with -clientjar then whatever you specify with -wsdllocation will have no effect as -clientjar will take precedence.
So we must focus on (2) and (3) because that's the only one being actually used ... at least if you use the generated code as-is.
It is interesting to note that the result of (2) is only a WSDL file. This file may have embedded links to XSD files but as far as I can tell such link will never be followed. The reason is that when we say a web service consumer needs the WSDL at runtime it really only needs the WSDL itself, at not the schema. The schema is "hardcoded" into the consumer and there's no way of changing it at runtime. Hence there's no reason to read schema information at runtime. (THIS IS FROM MY UNDERSTANDING)
Second thing to note about the WSDL that's included with (2): It is really just a copy of the original WSDL so it may not have endpoint you want. Actually in most cases it won't. This means that in this situation you'll need to set the endpoint yourself :
// Use no-arg constructor. Means it uses the WSDL bundled into the
// META-INF/wsdl directory rather than trying to retrieve WSDL over the
// network.
service = new HelloSvc_Service();
hello = service.getHelloSvcPort();
// Since we're using a bundled WSDL the web service URL cannot
// be derived from that (it would be wrong!). So we have to set
// it explicitly.
((BindingProvider) hello).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://myhellowebservice-address");
The documentation for this plugin is a joke. A workaround is to manually extract the contents from the client jar after it is created like follows:
<build>
<plugins>
<plugin>
<!--
Generates JAXWS classes for all of the WSDL files in $[project.base.dir}/src/wsdl.
-->
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<args>
<arg>-clientjar</arg>
<arg>${project.build.directory}/wsimport-client.jar</arg>
</args>
<wsdlUrls>
<wsdlUrl>https://webservice.com/service.wsdl</wsdlUrl>
</wsdlUrls>
</configuration>
</execution>
</executions>
<configuration>
<target>2.1</target>
<verbose>true</verbose>
</configuration>
</plugin>
<plugin>
<!--
Unjar the wsimport-client.jar created in the jaxws-maven-plugin to the WAR's classes folder
-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<target>
<unzip src="${project.build.directory}/wsimport-client.jar" dest="${project.build.directory}/classes" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
taken from here: https://gist.github.com/mpellegrini/5439304
I had the same issue, and I had to unzip the created jars and re-zip in one single jar (so, putting the wsdl file from the inner jar in the final jar).
Thanks to peterh comment, I think I understood the "trick": in Maven output I can see a log like
jaxws:wsimport args: [..., -Xnocompile, -clientjar wsdl.jar, ...]
so the wsimport command is launched without compiling che code, and in fact a wsdl.jar is created in the target/classes folder.
I think wsimport is just generating the sources and the jar with the wsdl, then the compilation and the packaging is done in the following steps.

Maven AppAssembler not finding class

Attempting to modify an existing Java/Tomcat app for deployment on Heroku following their tutorial and running into some issues with AppAssembler not finding the entry class. Running target/bin/webapp (or deploying to Heroku) results in Error: Could not find or load main class org.stopbadware.dsp.Main
Executing java -cp target/classes:target/dependency/* org.stopbadware.dsp.Main runs properly however. Here's the relevant portion of pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>org.stopbadware.dsp.Main</mainClass>
<name>webapp</name>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
My guess is mvn package is causing AppAssembler to not use the correct classpath, any suggestions?
Your artifact's packaging must be set to jar, otherwise the main class is not found.
<pom>
...
<packaging>jar</packaging>
...
</pom>
The artifact itself is added at the end of the classpath, so nothing other than a JAR file will have any effect.
Try:
mvn clean package jar:jar appassembler:assemble
Was able to solve this by adding "$BASEDIR"/classes to the CLASSPATH line in the generated script. Since the script gets rewritten on each call of mvn package I wrote a short script that calls mvn package and then adds the needed classpath entry.
Obviously a bit of a hack but after a 8+ hours of attempting a more "proper" solution this will have to do for now. Will certainly entertain any more elegant ways of correcting the classpath suggested here.
I was going through that tutorial some time ago and had very similar issue. I came with a bit different approach which works for me very nicely.
First of all, as it was mentioned before, you need to keep your POM's type as jar (<packaging>jar</packaging>) - thanks to that, appassembler plugin will generate a JAR file from your classes and add it to the classpath. So thanks to that your error will go away.
Please note that this tutorial Tomcat is instantiated from application source directory. In many cases that is enough, but please note that using that approach, you will not be able to utilize Servlet #WebServlet annotations as /WEB-INF/classes in sources is empty and Tomcat will not be able to scan your servlet classes. So HelloServlet servlet from that tutorial will not work, unless you add some additional Tomcat initialization (resource configuration) as described here (BTW, you will find more SO questions talking about that resource configuration).
I did a bit different approach:
I run a org.apache.maven.plugins:maven-war-plugin plugin (exploded goal) during package and use that generated directory as my source directory of application. With that approach my web application directory will have /WEB-INF/classes "populated" with classes. That in turn will allow Tomcat to perform scanning job correctly (i.e. Servlet #WebServlet annotations will work).
I also had to change a source of my application in the launcher class:
public static void main(String[] args) throws Exception {
// Web application is generated in directory name as specified in build/finalName
// in maven pom.xml
String webappDirLocation = "target/embeddedTomcatSample/";
Tomcat tomcat = new Tomcat();
// ... remaining code does not change
Changes to POM which I added - included maven-war-plugin just before appassembler plugin:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
...
Please note that exploded goal is called.
I hope that small change will help you.
One more comment on that tutorial and maven build: note that the tutorial was written to show how simple is to build an application and run it in Heroku. However, that is not the best approach to maven build.
Maven recommendation is that you should adhere to producing one artifact per POM. In your case there are should two artifacts:
Tomcat launcher
Tomcat web application
Both should be build as separate POMs and referenced as modules from your parent POM. If you look at the complexity of that tutorial, it does not make much sense to split that into two modules. But if your applications gets more and more complex (and the launcher gets some additional configurations etc.) it will makes a lot of sense to make that "split". As a matter of fact, there are some "Tomcat launcher" libraries already created so alternatively you could use of one them.
You can set the CLASSPATH_PREFIX environment variable:
export CLASSPATH_PREFIX=target/classes
which will get prepended to the classpath of the generated script.
The first thing is that you are using an old version of appassembler-maven-plugin the current version is 1.3.
What i don't understand why are you defining the
<assembleDirectory>target</assembleDirectory>
folder. There exists a good default value for that. So usually you don't need it. Apart from that you don't need to define an explicit execution which bounds to the package phase, cause the appassembler-maven-plugin is by default bound to the package phase.
Furthermore you can use the useWildcardClassPath configuration option to make your classpath shorter.
<configuration>
<useWildcardClassPath>true</useWildcardClassPath>
<repositoryLayout>flat</repositoryLayout>
...
</configruation>
And that the calling of the generated script shows the error is depending on the thing that the location of the repository where all the dependencies are located in the folder is different than in the generated script defined.

How to include external classes in my jar

I have a problem with a service I am trying to write. I am trying to create a service that runs in the background on a windows system but uses java. I have seen several ways of doing this, but decided on one method that seemed to meet my requirements. The service will check a database for items it needs to work on. When it finds an item in the DB that it needs to do it will run some system commands to take care of them.
I found a way to use the tomcat7.exe file to run a jar as a service and that worked pretty well for basic stuff. Anything I write and compile into my jar file "myService.jar" we'll can call it goes well enough. The problem is that we already have several classes written for accessing the DB and running commands that are precompiled in a library of classes called BGLib-1.0.jar.
I have used this library in writing several jenkins plugins and had no problems calling functions from it. They all work fine when I create an hpi file and deploy it in Jenkins. There the compiler (Eclipse using Maven) packages the BGLib jar in with the plugin jar and Jenkins figures out how to get them to see one another.
When I build my service jar, however, it doesn't work when I deploy it.
I run a command like this to install the Tomcat exe renames to myservice.exe:
d:\myService\bin>myService.exe //IS//myService --Install=D:\myService\bin\myService.exe --Description="run some commands
Java Service" --Jvm=auto --Classpath=D:\myService\jar\myService.jar;D:\myService\jar\BGLib-1.0.jar --StartMode=jvm --
StartClass=com.myCompany.myService.myService --StartMethod=windowsService --StartParams=start --StopMode=jvm --StopClass
=com.myCompany.myService.myService --StopMethod=windowsService --StopParams=stop --LogPath=D:\myService\logs --StdOutpu
t=auto --StdError=auto
When I deploy this with code solely within the myService.jar the service behaves as expected, but when I try to call functions within the BGLib-1.0.jar I get nothing. The jvm appears to crash or become unresponsive. Debugging is a little tricky but it looks like I am getting class not found errors.
I tried adding the entry below in the POM file to see if changing the classpath entry in the manifest would help, but it didn't change the manifest. I am still kind of clueless ass to how the manifest file works. Any documentation on that would be cool. I have been to Maven's site and it doesn't seem to have comprehensive documentation on the tags available. Is there something I need to change in the manifest to get my jar to see external classes? Or is there something I can add that will get Maven to compile the classes from that jar in with my jar?
thanks in advance.
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.myCompany.myService.myService</mainClass>
<customClasspathLayout>BGLib-1.0.jar</customClasspathLayout>
</manifest>
</archive>
</configuration>
To answer mainly the question of the title, you can the shade plugin to include dependencies into your final jar. You can even even relocate the class files (e.g. change package name) within the final jar so that the included classes don't conflict with different versions of the shaded dependency on the classpath. Not sure if this is the best solution for your particular problem though.
You can use the maven-dependency-plugin unpack-dependencies goal to include the contents of a dependency in the resulting artifact.
An example of how to do this would be:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>${project.artifactId}-fetch-deps</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<stripVersion>true</stripVersion>
<excludeTransitive>true</excludeTransitive>
<includeArtifactIds>protobuf-java</includeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
This will expand the protobuf-java dependency (flatten it) and include the contents in the resulting artifact generated by your build.
Looks to me you actually want to use the appassembler-maven-plugin, otherwise I'd go for the maven-shade-plugin.

Categories