HotSwapAgent failed to convert filePath to classPathPath - java

i am trying to use the HotSwapAgent in our Project.
We are using a Wildfly 10.x and our Project is deployed as an exploded EAR in which there is an exploded war.
I've added the following JVM-options:
-XXaltjvm=dcevm -javaagent:c:\dev\hotswap-agent.jar
When my WildFly is deploying i get the following Error:
HOTSWAP AGENT: 14:42:40.479 ERROR (org.hotswap.agent.plugin.spring.scanner.XmlBeanDefinationScannerAgent) - failed to convert filePath /C:/dev/projects/project_abc/abc/ABC/target/ABC_Exploded.ear/ABCWeb.war/WEB-INF/config/spring/soap-context.xml to classPath path
When i let the Wildfly run, later the following Error is shown and the Deployment fails.
rror creating bean with name 'systemConfigurationService' defined in ServletContext resource [/WEB-INF/config/spring/service-maintenance-context.xml]: Invocation of init method failed; nested exception is java.lang.reflect.UndeclaredThrowableException
Does anyone know how to configure this right ?
I've read that you can put an extraClassPath into the properties of the HotswapAgent but i've no clue what i should set.

You have to change the convertToClasspathURL in org.hotswap.agent.plugin.spring.scanner.XmlBeanDefinationScannerAgent in order to your needs.
Seems in your case above just the following to the method:
paths = filePath.split("WEB-INF/config/spring");
if (paths.length == 2) {
return paths[1];
}
convertToClasspathURL ( after modifying it for your classpath needs ) :
private static String convertToClasspathURL(String filePath) {
String[] paths = filePath.split("src/main/resources/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("WEB-INF/classes/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("target/classes/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("target/test-classes/");
if (paths.length == 2) {
return paths[1];
}
paths = filePath.split("WEB-INF/config/spring");
if (paths.length == 2) {
return paths[1];
}
LOGGER.error("failed to convert filePath {} to classPath path", filePath);
return filePath;
}
Hope it solves your problem!

Related

Why path on server throw NullPonterException?

I have a problem with the path to the file. Locally (Windows), the tests pass, but when I upload it to the server(Linux), I have:
NullPointerException: Cannot get property 'text' on null object
Sample code:
public final String MAIN = "dir1/dir2/dir3/"
public final String CAT_1 = MAIN + "subdirectory/"
somewhere in the method ...
def object = Utils.class.getClassLoader().getResource(CAT_1 + "file.xml").text
unmarshaller.unmarshal(new StringSource(object), SomeClass.class).value
Why path on server throw NullPonterException?
Utils.class.getClassLoader().getResource(CAT_1 + "file.xml").text will throw a NullPointerException if CAT_1 + "file.xml" can't be loaded because getResource is going to return null.
Apparently that resource is not available at the path you are expecting it to be available at.

Spring List all files in static directory

I use Spring with embeded Tomcat and a War file in prodution.
I need to list all files in the "static" directory. It's like 4 days I m on it
This kind of code not working :
Stream.of(new File(dir).listFiles()
It lists the files where the war is located but the static directory is inside the war
With this code I arrive to read a file inside the war :
Thread.currentThread().contextClassLoader?.getResourceAsStream(path)?.bufferedReader()?.use(BufferedReader::readText)
But it's not working with a directory
And now i have no idea how i can list all files inside the static directory
I found a solution
Not sure it's the best and clean but it's worked
I use 2 way to do it, one for developpment and the other when it's package inside war
loadFilesFromDirectory("/static")
fun listFilesFromDirectory(path: String, request: HttpServletRequest? = null): List<String> {
return if (request == null || request.requestURL.contains("localhost")) {
//Don't work on war but work on IDE
Thread.currentThread().contextClassLoader?.getResourceAsStream(path)
?.bufferedReader()?.use(BufferedReader::readText)?.split("\n")
?.filter { it.endsWith(".html") }
?: throw Exception("Non trouvé :$path")
} else {
//Not work on IDE but work on war
val root: URL = request.servletContext.getResource("/WEB-INF/classes/$path")
var rootPath: String = root.path
rootPath = rootPath.substring(rootPath.indexOf("/WEB-INF"), rootPath.length)
return request.servletContext.getResourcePaths(rootPath).map {
it.replace(".*/", "")
}.filter { it.endsWith(".html") }
}
}

getResourceAsStream returning null despite called file being in same dir as class getResourceAsStream is called in

I imported an Android sample coded by Amazon involving AWS's DynamoDB which I got from here and was presumably written for Eclipse:
https://github.com/awslabs/aws-sdk-android-samples/tree/master/DynamoDBMapper_UserPreference
Since Android Studio (0.8.1) uses gradle instead of ant, naturally things got auto-moved around in terms of dir structure when importing so (part of) it looks like this:
PropertyLoader gets the TVM credential info it needs to connect to the database DynamoDB from AwsCredentials.properties. Relevant methods:
public class PropertyLoader {
private boolean hasCredentials = false;
private String tokenVendingMachineURL = null;
private boolean useSSL = false;
private String testTableName = null;
private static PropertyLoader instance = null;
public static PropertyLoader getInstance() {
if ( instance == null ) {
instance = new PropertyLoader();
}
return instance;
}
public PropertyLoader() {
try {
Properties properties = new Properties();
properties.load( this.getClass().getResourceAsStream( "AwsCredentials.properties" ) );
this.tokenVendingMachineURL = properties.getProperty( "tokenVendingMachineURL" );
this.useSSL = Boolean.parseBoolean( properties.getProperty( "useSSL" ) );
this.testTableName = properties.getProperty( "testTableName" );
if ( this.tokenVendingMachineURL == null || this.tokenVendingMachineURL.equals( "" ) || this.tokenVendingMachineURL.equals( "CHANGEME" ) || this.testTableName.equals( "" ) ) {
this.tokenVendingMachineURL = null;
this.useSSL = false;
this.hasCredentials = false;
this.testTableName = null;
}
else {
this.hasCredentials = true;
}
}
catch ( Exception exception ) {
Log.e( "PropertyLoader", "Unable to read property file." );
}
}
However the getResourceAsStream line properties.load( this.getClass().getResourceAsStream( "AwsCredentials.properties" ) ); returns null. As you can see in my screenshot, AwsCredentials.properties is in the same dir as PropertyLoader and matches the case, which is all that should be required based on my readings of the method:
http://mindprod.com/jgloss/getresourceasstream.html
getResourceAsStream() is always returning null
I have tried other things such as prefixing "\" (i.e. properties.load( this.getClass().getResourceAsStream( "\AwsCredentials.properties" ) ); and copying the credentials file and placing in the src folder (you can't see it in this screenshot because the explorer sorts by filetype(?) and places 'main' first, but it's there) as per this:
getResourceAsStream returning null
However, that hasn't fixed the issue either. Having tried these options and done research, I'm confused as to why it's returning null. How can I fix this?
Created a dir called resources under /src/main/ and placed AwsCredentials.properties there and used
properties.load( PropertyLoader.class.getClassLoader().getResourceAsStream( "AwsCredentials.properties" ) );
instead of
properties.load( this.getClass().getResourceAsStream("AwsCredentials.properties" ) );
Not as elegant as I would like, but it works.
For up to a day I was struggling with this as well. And finally I was able to resolve this very neatly. The problem is not in the JAVA but in the all project structure. E.g. in Android Studio the whole project is under src/main/java whereas main is a flavour of the project. So if you've file(-s) to read from in source's package (e.g.) com/my/example/app you have to edit the build.gradle file for read (clazz.getResourceAsStream(file)) to work properly. I.e. under android define sourceSets like this:
android {
/* ... Your stuff ... */
sourceSets {
// Lets have two flavours to make it more clear
main {
resources.srcDirs = ['src/main/java']
}
flavourFoo {
resources.srcDirs = ['src/flavourFoo/java']
}
}
}
Hope this helps!

Empty Context String Warning

I try to configure a jetty context (programmatically) for using a servlet serving the root context.
For the context path I set "/" and for the servlet mapping "/*". This works exactly the way I want it to but Jetty is complaining (warning) about the context path ending with '/'. When I set the context path to "" (empty string), it results in the warning about an empty string.
The documentation section of Jetty about this issue states:
Be aware
Java Servlet Specification 2.5 discourages an empty context path string, and Java Servlet Specification 3.0 effectively forbids it.
The portion of the Jetty source is:
public void setContextPath(String contextPath)
{
if (contextPath == null)
throw new IllegalArgumentException("null contextPath");
if (contextPath.endsWith("/*"))
{
LOG.warn(this+" contextPath ends with /*");
contextPath=contextPath.substring(0,contextPath.length()-2);
}
else if (contextPath.endsWith("/"))
{
LOG.warn(this+" contextPath ends with /");
contextPath=contextPath.substring(0,contextPath.length()-1);
}
if (contextPath.length()==0)
{
LOG.warn("Empty contextPath");
contextPath="/";
}
_contextPath = contextPath;
if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
{
Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
((ContextHandlerCollection)contextCollections[h]).mapContexts();
}
}
So the question is, what context path should I set in order to map to the root of the context. Currently everything works fine but having a forbidden context path setting by specification or a Jetty warning, I guess I need something different.
The docs says that
The context path is the prefix of a URL path that is used to select
the context(s) to which an incoming request is passed. Typically a URL
in a Java servlet server is of the format
http://hostname.com/contextPath/servletPath/pathInfo, where each of
the path elements can be zero or more / separated elements. If there
is no context path, the context is referred to as the root context.
The root context must be configured as "/" but is reported as the
empty string by the servlet API getContextPath() method.
So, I guess you are fine using "/" .
http://www.eclipse.org/jetty/documentation/current/configuring-contexts.html
I tried to add a bug request for this after I noticed (thanks #Ozan!) that "/" is used in the case of setting the context path to "". So I thought it was a bug and yes it is. A bug report already exists for this issue and it was fixed in 9.0.6 which is available since 2013 Sep 30. So I just upgraded the jetty version and the warning is now gone.
The Jetty code now checks if the length of the path is greater 1:
public void setContextPath(String contextPath)
{
if (contextPath == null)
throw new IllegalArgumentException("null contextPath");
if (contextPath.endsWith("/*"))
{
LOG.warn(this+" contextPath ends with /*");
contextPath=contextPath.substring(0,contextPath.length()-2);
}
else if (contextPath.length()>1 && contextPath.endsWith("/"))
{
LOG.warn(this+" contextPath ends with /");
contextPath=contextPath.substring(0,contextPath.length()-1);
}
if (contextPath.length()==0)
{
LOG.warn("Empty contextPath");
contextPath="/";
}
_contextPath = contextPath;
if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
{
Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
((ContextHandlerCollection)contextCollections[h]).mapContexts();
}
}

UnitTest (groovy + grails) - Cannot teardown metaclass

I'm having a problem when I try to clean the class.
void testFileExists() {
FileObject file = EasyMock.createMock(FileObject.class)
VfsFileSystemManager.metaClass.getFile = {String s, String a ->return file}
FileObject.metaClass.exists = {-> return true}
assertEquals true, siteManagerHelper.fileExists(STRING, STRING)
}
void testFileNotExists() {
FileObject file = EasyMock.createMock(FileObject.class)
VfsFileSystemManager.metaClass.getFile = {String s, String a ->return file}
FileObject.metaClass.exists = {-> return false}
assertEquals false, siteManagerHelper.fileExists(STRING, STRING)
}
When I run one at the time, they work fine, but if I run both at the same time, exists() always return true (if I change the first .metaclass for false, it returns false). So I assume it's not tearing down the metaclass.
The class extends GroovyTestCase, and I checked that I should add:
def remove = GroovySystem.metaClassRegistry.&removeMetaClass
remove FileObject
But it's not working.
Please, help!
EDIT:
I'm using grails 1.3.7 and groovy 1.6.8
private boolean fileExists(String path, String file){
if(path != null && path != ""){
FileObject fileToCheck = fsManager.getFile(path, file)
boolean fileExists = fileToCheck.exists()
logger.debug "File exists? ${fileExists}"
return fileExists
}
logger.debug "The path is null or empty"
return false
}
I faced a similar issue (Grails 2.2.0) and I was able to surmount it by following the below:
Use GroovySystem.metaClassRegistry.removeMetaClass(FileObject.class) in the end of the test method to tear down
Use FileObject.metaClass = null in test class tearDown()
I still wonder why do we need to use both tearDown simultaneously.
Note:- In my case I metaClassed a Groovy Object as compared to a Java Object.

Categories