Is there a way to get which classes a ClassLoader has loaded? - java

I am trying to implement some unit testing for an old framework. I am attempting to mock out the database layer. Unfortunately our framework is a bit old and not quite using best practices so there is no clear separation of concerns. I am bit worried that trying to mock out the database layer might make the JVM load a huge number of classes that won't even be used.
I don't really understand class loaders that well so this might not be a problem. Is there a way to take a peak at all the classes a particular ClassLoader has loaded to prove what is going on under the hood?

You can create your own Classloader and use that to load during the unit test. Have your own custom Classloader print out what it's doing.
Or if you just want to know which classes are loaded, do:
java -verbose:class

Be warned that using
java -verbose
Will produce an enormous amount of output. Log the output to a file and then use grep. If you have the 'tee' filter you could try this:
java -verbose | tee classloader.log
grep class classloader.log

I am not sure. But there is one way I see it could be done. It maybe overrly ridiculous though. You can try aspects and put a pointcut for loadclass.
Also maybe the jvm argument -verbose maybe helpful.

As an alternative way, for a particular Class-loader as you mentioned, you can use this code snippet. Just change value of obj variable if you want.
Object obj = this;
ClassLoader classLoader = obj.getClass().getClassLoader();
File file = new File("classloderClasses.txt");
if (file.exists()) {
file.delete();
}
if (classLoader != null) {
try {
Class clClass = classLoader.getClass();
while (clClass != ClassLoader.class) {
clClass = clClass.getSuperclass();
}
java.lang.reflect.Field classesField = clClass.getDeclaredField("classes");
classesField.setAccessible(true);
Vector classes = (Vector) classesField.get(classLoader);
FileOutputStream fos = new FileOutputStream("classloderClasses.txt", true);
fos.write(("******************** " + classLoader.toString() + " ******************** " + "\n").getBytes());
fos.write(Arrays.toString(classes.toArray()).getBytes());
fos.close();
} catch (Exception exception) {
exception.printStackTrace();
// TODO
}
}

Related

Problems with SmbFile.createNewFile() behaviour

I wonder what the catch is with createNewFile() in recent versions of jCIFS and ng (SMB2 specifically). The documentation says it should fail on execution if a file already exists, but that is not the case in my code, the file is always overwritten instead of throwing a SmbException. I need to be able to rename the file so it is not overwritten, but due to server load and quantity I cannot use exists(). This snippet worked perfectly on SMB1:
for (int i = 0; !fileCreated && (i < maxCopies); i++) {
try {
smbFile.createNewFile();
fileCreated = true;
} catch (SmbException e) {
smbFile = new SmbFile(smbFilePath.concat(String.valueOf(i)), auth);
}
}
I've been searching high and low and trying out different versions of SMB2, but createNewFile() always does the opposite of what the javadoc says it should. Is there a simple way (using attributes for example) to make it work just as in SMB1?
EDIT: Solution by jcifs-ng developer on GitHub
Apparently I got the behavior wrong when implementing the SMB2
version. Create disposition should be FILE_CREATE not FILE_OPEN_IF,
then ( O_EXCL in SMB1). Let me look into making that change, and how
much havoc this will cause. You could potentially work around this by
explicitly calling openOutputStream and passing O_EXCL as open flag.

Why sun.swing.AccessibleMethod is gone from JDK 8?

I'm wondering if someone know why sun.swing.AccessibleMethod is gone from JDK 8 and if there is some alternative to this class in JDK 8?
I can't find any information about that anywhere.
I use this class in my own implementation DropHandler. Code snippet where I use sun.swing.AccessibleMethod looks like this:
private DropLocation getDropLocation(DropTargetEvent e)
{
DropLocation dropLocation = null;
if (this.component != null)
{
try
{
Point p = e instanceof DropTargetDragEvent ? ((DropTargetDragEvent)e).getLocation() : ((DropTargetDropEvent) e).getLocation();
AccessibleMethod method = new AccessibleMethod(JComponent.class,
"dropLocationForPoint",
Point.class);
dropLocation = (DropLocation) method.invokeNoChecked(this.component, p);
}
catch (NoSuchMethodException ex)
{
LOGGER.info(ex.getMessage());
}
}
return dropLocation;
}
As explained in this official post from Oracle: Why Developers Should Not Write Programs That Call 'sun' Packages (thanks to #greg-449 for providing this info):
The sun.* packages are not part of the supported, public interface.
A Java program that directly calls into sun.* packages is not guaranteed to work on all Java-compatible platforms. In fact, such a program is not guaranteed to work even in future versions on the same platform.
So, you should not have relied on sun.swing.AccessibleMethod class in the first place.
More info:
It is a bad practice to use Sun's proprietary Java classes?
As a solution for your problem, you can do the following:
Use the source code of sun.swing.AccessibleMethod to create a custom class.
Replace the usage of AccessibleMethod by your own custom class.
What’s the point about this AccessibleMethod class?
The following uses standard Java API which exists since Java 1.2:
try {
Method method = JComponent.class
.getDeclaredMethod("dropLocationForPoint", Point.class);
method.setAccessible(true);
dropLocation = (DropLocation) method.invoke(this.component, p);
} catch(NoSuchMethodException|IllegalAccessException|InvocationTargetException ex) {
Logger.info(ex.getMessage());
}
However, don’t come back and ask why JComponent.dropLocationForPoint has been removed, if that happens in the future. If you are accessing non-standard APIs you may encounter such problems. To be exact, there were always Java implementations not having these features your code relies on...

Create a database / execute a bunch of mysql statements from Java

I have a library that needs to create a schema in MySQL from Java. Currently, I have a dump of the schema that I just pipe into the mysql command. This works okay, but it is not ideal because:
It's brittle: the mysql command needs to be on the path: usually doesn't work on OSX or Windows without additional configuration.
Also brittle because the schema is stored as statements, not descriptively
Java already can access the mysql database, so it seems silly to depend on an external program to do this.
Does anyone know of a better way to do this? Perhaps...
I can read the statements in from the file and execute them directly from Java? Is there a way to do this that doesn't involve parsing semicolons and dividing up the statements manually?
I can store the schema in some other way - either as a config file or directly in Java, not as statements (in the style of rails' db:schema or database.yml) and there is a library that will create the schema from this description?
Here is a snippet of the existing code, which works (when mysql is on the command line):
if( db == null ) throw new Exception ("Need database name!");
String userStr = user == null ? "" : String.format("-u %s ", user);
String hostStr = host == null ? "" : String.format("-h %s ", host);
String pwStr = pw == null ? "" : String.format("-p%s ", pw);
String cmd = String.format("mysql %s %s %s %s", hostStr, userStr, pwStr, db);
System.out.println(cmd + " < schema.sql");
final Process pr = Runtime.getRuntime().exec(cmd);
new Thread() {
public void run() {
try (OutputStream stdin = pr.getOutputStream()) {
Files.copy(f, stdin);
}
catch (IOException e) { e.printStackTrace(); }
}
}.start();
new Thread() {
public void run() {
try (InputStream stdout = pr.getInputStream() ) {
ByteStreams.copy(stdout, System.out);
}
catch (IOException e) { e.printStackTrace(); }
}
}.start();
int exitVal = pr.waitFor();
if( exitVal == 0 )
System.out.println("Create db succeeded!");
else
System.out.println("Exited with error code " + exitVal);
The short answer (as far as i know) is no.
You will have to do some parsing of the file into separate statements.
I have faced the same situation and you can find many questions on this topic here on SO.
some like here will show a parser. others can direct to tools Like this post from apache that can convert the schema to an xml format and then can read it back.
My main intention when writing this answer is to tell that I chose to use the command line in the end.
extra configuration: maybe it is an additional work but you can do it by config or at runtime based on the system you are running inside. you do the effort one time and you are done
depending on external tool: it is not as bad as it seems. you have some benefits too.
1- you don't need to write extra code or introduce additional libraries just for parsing the schema commands.
2- the tool is provided by the vendor. it is probably more debugged and tested than any other code that will do the parsing.
3- it is safer on the long run. any additions or changes in the format of dump that "might" break the parser will most probably be supported with the tool that comes with the database release. you won't need to do any change in your code.
4- the nature of the action where you are going to use the tool (creating schema) does not suggest frequent usage, minimizing the risk of it becoming a performance bottle neck.
I hope you can find the best solution for your needs.
Check out Yank, and more specifically the code examples linked to on that page. It's a light-weight persistence layer build on top of DBUtils, and hides all the nitty-gritty details of handling connections and result sets. You can also easily load a config file like you mentioned. You can also store and load SQL statements from a properties file and/or hard code the SQL statements in your code.

Best practice: Creation of SAX parser for XMLReader

I'm using the Amazon S3 SDK in two separate wars running on the same Tomcat. I initialize an AmazonS3Client in the #PostConstruct of one of my Spring services.
If I run these wars separately, everything usually works fine. If I run them together, one of them - the second one to start up - throws the following exception:
com.amazonaws.AmazonClientException: Couldn't initialize a sax driver for the XMLReader
I have a workaround where I set the following System property if this happens, after catching the AmazonClientException:
try {
init();
} catch (AmazonClientException ase) {
System.setProperty("org.xml.sax.driver", "com.sun.org.apache.xerces.internal.parsers.SAXParser");
init();
}
But this is of course horrible. Is there a better way to do this? Why does this occur in these circumstances?
UPDATE: At first, it seemed that moving the intitalization of the AmazonS3Client out of the #PostConstruct and initializing it lazily prevented this error completely. But apparently it still occurs sometimes - even when I only run one war instead of both.
The XMLReader goes through a series of steps to identify which drive to use. Quoting the docs
If the system property org.xml.sax.driver has a value, that is used
as an XMLReader class name.
The JAR "Services API" is used to look
for a class name in the META-INF/services/org.xml.sax.driver file in
jarfiles available to the runtime.
SAX parser distributions are
strongly encouraged to provide a default XMLReader class name that
will take effect only when previous options (on this list) are not
successful.
Finally, if ParserFactory.makeParser() can return a
system default SAX1 parser, that parser is wrapped in a
ParserAdapter. (This is a migration aid for SAX1 environments, where
the org.xml.sax.parser system property will often be usable.)
Looking at the code for the AWS SDK ...
public XmlResponsesSaxParser() throws AmazonClientException {
// Ensure we can load the XML Reader.
try {
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e) {
// oops, lets try doing this (needed in 1.4)
System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
try {
// Try once more...
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e2) {
throw new AmazonClientException("Couldn't initialize a sax driver for the XMLReader");
}
}
}
There are a couple of things I don't like about that code.
The root cause of SaxException e is eaten up.
The root cause of SaxException e2 is also eaten up. The least the code should do is print a warning mentioning the root cause.
Using System.setProperty() inside level framework code can cause some hard to debug issues.
These points make it harder to debug the issue. The best educated guess I can make is that the crimson parser is accessible in one class loading path but absent in the other. A conclusive way to find the problem would be to set a breakpoint on the code that tries to instantiate the reader and find what the underlying root cause is.
as it uses the singleton model, the only way to isolate this calls would be to have entire set of SAX-related JARs within the WARs themselves (they would load to different classloaders). It worked for me the time I had the same problem. This will have a PermGen impact, but what to do..
Or if you don't mind to change the S3 lib, make this method static synchronized and share the lib.
If the Amazon guys make this calls synchronized this wouldn't be issue.
Execption can be reolved by adding "xerces-2.9.0.jar" to the classpath

Query Windows Search from Java

I would like to get to query Windows Vista Search service directly ( or indirectly ) from Java.
I know it is possible to query using the search-ms: protocol, but I would like to consume the result within the app.
I have found good information in the Windows Search API but none related to Java.
I would mark as accepted the answer that provides useful and definitive information on how to achieve this.
Thanks in advance.
EDIT
Does anyone have a JACOB sample, before I can mark this as accepted?
:)
You may want to look at one of the Java-COM integration technologies. I have personally worked with JACOB (JAva COm Bridge):
http://danadler.com/jacob/
Which was rather cumbersome (think working exclusively with reflection), but got the job done for me (quick proof of concept, accessing MapPoint from within Java).
The only other such technology I'm aware of is Jawin, but I don't have any personal experience with it:
http://jawinproject.sourceforge.net/
Update 04/26/2009:
Just for the heck of it, I did more research into Microsoft Windows Search, and found an easy way to integrate with it using OLE DB. Here's some code I wrote as a proof of concept:
public static void main(String[] args) {
DispatchPtr connection = null;
DispatchPtr results = null;
try {
Ole32.CoInitialize();
connection = new DispatchPtr("ADODB.Connection");
connection.invoke("Open",
"Provider=Search.CollatorDSO;" +
"Extended Properties='Application=Windows';");
results = (DispatchPtr)connection.invoke("Execute",
"select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
"from SystemIndex " +
"where contains('Foo')");
int count = 0;
while(!((Boolean)results.get("EOF")).booleanValue()) {
++ count;
DispatchPtr fields = (DispatchPtr)results.get("Fields");
int numFields = ((Integer)fields.get("Count")).intValue();
for (int i = 0; i < numFields; ++ i) {
DispatchPtr item =
(DispatchPtr)fields.get("Item", new Integer(i));
System.out.println(
item.get("Name") + ": " + item.get("Value"));
}
System.out.println();
results.invoke("MoveNext");
}
System.out.println("\nCount:" + count);
} catch (COMException e) {
e.printStackTrace();
} finally {
try {
results.invoke("Close");
} catch (COMException e) {
e.printStackTrace();
}
try {
connection.invoke("Close");
} catch (COMException e) {
e.printStackTrace();
}
try {
Ole32.CoUninitialize();
} catch (COMException e) {
e.printStackTrace();
}
}
}
To compile this, you'll need to make sure that the JAWIN JAR is in your classpath, and that jawin.dll is in your path (or java.library.path system property). This code simply opens an ADO connection to the local Windows Desktop Search index, queries for documents with the keyword "Foo," and print out a few key properties on the resultant documents.
Let me know if you have any questions, or need me to clarify anything.
Update 04/27/2009:
I tried implementing the same thing in JACOB as well, and will be doing some benchmarks to compare performance differences between the two. I may be doing something wrong in JACOB, but it seems to consistently be using 10x more memory. I'll be working on a jcom and com4j implementation as well, if I have some time, and try to figure out some quirks that I believe are due to the lack of thread safety somewhere. I may even try a JNI based solution. I expect to be done with everything in 6-8 weeks.
Update 04/28/2009:
This is just an update for those who've been following and curious. Turns out there are no threading issues, I just needed to explicitly close my database resources, since the OLE DB connections are presumably pooled at the OS level (I probably should have closed the connections anyway...). I don't think I'll be any further updates to this. Let me know if anyone runs into any problems with this.
Update 05/01/2009:
Added JACOB example per Oscar's request. This goes through the exact same sequence of calls from a COM perspective, just using JACOB. While it's true JACOB has been much more actively worked on in recent times, I also notice that it's quite a memory hog (uses 10x as much memory as the Jawin version)
public static void main(String[] args) {
Dispatch connection = null;
Dispatch results = null;
try {
connection = new Dispatch("ADODB.Connection");
Dispatch.call(connection, "Open",
"Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
results = Dispatch.call(connection, "Execute",
"select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
"from SystemIndex " +
"where contains('Foo')").toDispatch();
int count = 0;
while(!Dispatch.get(results, "EOF").getBoolean()) {
++ count;
Dispatch fields = Dispatch.get(results, "Fields").toDispatch();
int numFields = Dispatch.get(fields, "Count").getInt();
for (int i = 0; i < numFields; ++ i) {
Dispatch item =
Dispatch.call(fields, "Item", new Integer(i)).
toDispatch();
System.out.println(
Dispatch.get(item, "Name") + ": " +
Dispatch.get(item, "Value"));
}
System.out.println();
Dispatch.call(results, "MoveNext");
}
} finally {
try {
Dispatch.call(results, "Close");
} catch (JacobException e) {
e.printStackTrace();
}
try {
Dispatch.call(connection, "Close");
} catch (JacobException e) {
e.printStackTrace();
}
}
}
As few posts here suggest you can bridge between Java and .NET or COM using commercial or free frameworks like JACOB, JNBridge, J-Integra etc..
Actually I had an experience with with one of these third parties (an expensive one :-) ) and I must say I will do my best to avoid repeating this mistake in the future. The reason is that it involves many "voodoo" stuff you can't really debug, it's very complicated to understand what is the problem when things go wrong.
The solution I would suggest you to implement is to create a simple .NET application that makes the actual calls to the windows search API. After doing so, you need to establish a communication channel between this component and your Java code. This can be done in various ways, for example by messaging to a small DB that your application will periodically pull. Or registering this component on the machine IIS (if exists) and expose simple WS API to communicate with it.
I know that it may sound cumbersome but the clear advantages are: a) you communicate with windows search API using the language it understands (.NET or COM) , b) you control all the application paths.
Any reason why you couldn't just use Runtime.exec() to query via search-ms and read the BufferedReader with the result of the command? For example:
public class ExecTest {
public static void main(String[] args) throws IOException {
Process result = Runtime.getRuntime().exec("search-ms:query=microsoft&");
BufferedReader output = new BufferedReader(new InputStreamReader(result.getInputStream()));
StringBuffer outputSB = new StringBuffer(40000);
String s = null;
while ((s = output.readLine()) != null) {
outputSB.append(s + "\n");
System.out.println(s);
}
String result = output.toString();
}
}
There are several libraries out there for calling COM objects from java, some are opensource (but their learning curve is higher) some are closed source and have a quicker learning curve. A closed source example is EZCom. The commercial ones tend to focus on calling java from windows as well, something I've never seen in opensource.
In your case, what I would suggest you do is front the call in your own .NET class (I guess use C# as that is closest to Java without getting into the controversial J#), and focus on making the interoperability with the .NET dll. That way the windows programming gets easier, and the interface between Windows and java is simpler.
If you are looking for how to use a java com library, the MSDN is the wrong place. But the MSDN will help you write what you need from within .NET, and then look at the com library tutorials about invoking the one or two methods you need from your .NET objects.
EDIT:
Given the discussion in the answers about using a Web Service, you could (and probably will have better luck) build a small .NET app that calls an embedded java web server rather than try to make .NET have the embedded web service, and have java be the consumer of the call. For an embedded web server, my research showed Winstone to be good. Not the smallest, but is much more flexible.
The way to get that to work is to launch the .NET app from java, and have the .NET app call the web service on a timer or a loop to see if there is a request, and if there is, process it and send the response.

Categories

Resources