views:

1074

answers:

4

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? :)

A: 

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();
    }
}
Chris Bunch
Read second line. What I have manage to do is to invoke the Windows Explorer to display the results. Not exactly what I need ( read end on line #2 ). Or, am I missing something here?
OscarRyz
Ah, you're right. I'm not familiar with Windows Search and am running on a Mac, so I didn't realize it would invoke Explorer. Sorry about that!
Chris Bunch
No problem. Thanks anyway for the help. BTW, to make your post run it should look like: http://pastebin.com/fa34637e
OscarRyz
+15  A: 

You may want to look at one of the Java-COM integration technologies. I have personally worked with JACOB (JAva COm Bridge):

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:

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();
  }
 }
}
Jack Leow
I should have added I don't know much of windows programming :-S I've seen this library before, but never got much further because I'm not really sure what to do next? Can you make the sample search on MSDN documentation to work with jacob?
OscarRyz
This was very interesting! I'm a newbie who is studying computer science and I wonder where I can learn more about "going-into" windows and do stuff like that from java or any other language. Any titles for books or webpages? I've used days now reading on msdn, but it's not for beginners.. :)
Johannes
I'm not aware of any, I really just had a quick look at the Jawin documentation, and then the COM component API references available from Microsoft. It's a start, but I suspect I'll run into a lot more problems if I were trying anything more complex.
Jack Leow
It worked pretty well. Now I'm trying to get more columns based on this: http://bit.ly/Rbeu8 I'm wondering if JNA, JACOB and JAWIN and others are dated. Most of the changes have a couple of years old. I'm about to mark this as accepted. Do you happen to have a JACOB sample :P :) –
OscarRyz
How do I change classpath and path? Is it something that will effect my whole "java-system" or just current project..?
Johannes
I figured it out how to change classpath, now it's only the "path"-part.. :)Will 'java -Djava.library.path=c:/jawin/bin SomeMainClass' affect my whole system? What exactly is a "path"?
Johannes
@Johannes You can do either -Djava.library.path (as you did), or update your PATH environment variable, but you don't have to do both. What you've done is fine, and IMO preferable. What you did affects only your one JVM execution (it won't affect other Java programs you run on your system). I hope this answers your question.
Jack Leow
@Oscar Reyes Thanks for - http://bit.ly/Rbeu8, I was looking all over for that. BTW, I too realize that most of these COM integration technologies are very outdated, but I think the reason for that is that COM as a technology has pretty much been set in stone for the past few years now, so naturally the technologies that integrate with it too have not changed. Hopefully someone else will have a better answer for you though.
Jack Leow
@Jack Leow: Thanks :D
Johannes
@Jack. I have just noticed due to my lack of attention, you've got 250 pts instead of 500. I'm not too fond of my rep anymore ( I have already gone beyond 10k mark ) I'll open a new question on monday and award you the missing points. :) Thanks for the Jacob sample. I'll take a look at it in the weekend. :)
OscarRyz
Thanks, let me know where to look.
Jack Leow
@Jack: Here http://stackoverflow.com/questions/821969/query-mac-os-x-spotligth-from-java A day have to pass to make it featured though.
OscarRyz
A: 

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.

Yishai
Not exactly looking for a java/com library ( at least that's not the rationale of the question ) but consume windows search from Java. ( although the few answers I've got go in java/com lib direction )
OscarRyz
The only way to consume a windows search like that is with a windows API, so the only way to interact with that windows API from java is something like COM, DCOM or CORBA or some kind of socket layer (like web services). That is why we are all pointing you to a java/com bridge.
Yishai
+3  A: 

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.

LiorH
I have actually think on the second option, using ws. I know a few light weight java frameworks/webservers that could be used, I don't know if there is something else than IIS for the same purpose. IIS is a full futured webserver, while all that is needed a basic http communication.
OscarRyz
there are many light weight Java servers, but if I understand your problem, you need the .NET code (not Java) to run on the web server, so IIS would be the first and simplest choice
LiorH
Hey Lior,While I'd tend to agree with you if this is something more complicated, I think this is simple enough (just an OLE DB call), as such I think a Java/COM call shouldn't be a problem. I have been reading up on this though, and it does seem like Java-COM integration can be a nightmare, especially if threading comes into play (e.g., multiple Java threads sharing a COM objecct).
Jack Leow
Hey Jack, you are right, after all we have a product that was officially distributed with one of these bridging technologies and it still works. But we faced many problems along the way. It's just a frustrating feeling when you are not "in control" over your code.Anyways, I tried to present an alternative, not to disqualify your answer.
LiorH