root/release-kits/shared/search4j/search4j.cpp @ 15093

Revision 15093, 13.0 KB (checked in by oranfry, 11 years ago)

importing the search4j tool I wrote for the release kits

Line 
1/*
2* Search4j utility
3* Command Line utility to search a system for java, launch a jar, or compare java versions
4* base on launch4j
5*/
6
7#include <iostream>
8#include <fstream>
9#include <sstream>
10#include <string>
11#include <windows.h>
12using namespace std;
13
14
15//minimal launch4j stuff
16#define NO_JAVA_FOUND 0
17#define FOUND_JRE 1
18#define FOUND_SDK 2
19int foundJava = NO_JAVA_FOUND;
20char foundJavaVer[128] = {0};
21
22
23//global variables
24bool verbose = false;
25bool use_minimum = false;
26
27enum JvmProperty {
28    JavaHome,
29    Version,
30    Executable
31};
32
33enum Action {
34    Find,
35    Launch,
36    Compare
37};
38
39void replace_all ( std::string & str, std::string const & pattern, std::string const & replacement ) {
40
41    std::string::size_type start = str.find( pattern, 0 );
42
43    while ( start != str.npos ) {
44        str.replace( start, pattern.size(), replacement );
45        start = str.find( pattern, start+replacement.size() );
46    }
47
48}
49
50int process( string command, string &output ) {
51   
52    FILE   *pPipe;
53
54    /* Run command so that it writes its output to a pipe. Open this
55    * pipe with read text attribute so that we can read it
56    * like a text file. */
57    char cmd[1024]; strcpy(cmd, command.c_str());
58    //if ( verbose ) cout << "process(): running '" << command << "'" << endl;
59    if( (pPipe = _popen( cmd, "rt" )) == NULL ) {
60        if ( verbose ) cout << "could not start process" << endl;
61        _pclose( pPipe );
62        return -1;
63    }
64    //if ( verbose ) cout << "started process" << endl;
65
66    /* Read pipe until end of file. */
67    while( !feof( pPipe ) ) {
68        char psBuffer[128];
69        //if ( verbose ) cout << "get some data" << endl;
70        if( fgets( psBuffer, 128, pPipe ) != NULL ) {
71           
72            //if ( verbose ) cout << "got: " << psBuffer << endl;
73            output.append( psBuffer );
74           
75        } else {
76            //if ( verbose ) cout << "none left" << endl;
77        }
78       
79    }
80
81    /* Close pipe and return return value of pPipe. */
82    int code = _pclose( pPipe );
83    return code;
84}
85
86class Jvm {
87
88    string javaHome;
89   
90    // version string. era.major.minor_update. eg: 1.4.2_02
91    int era;
92    int major;
93    int minor;
94    int update;
95
96    bool isJdk;
97    bool healthy;   
98
99
100    public:
101    Jvm() {
102        healthy = false;
103    }
104
105    void setJavaHome( string jh ) {
106        healthy = true;
107        javaHome = jh;
108        setVersionFromExeOuput();
109    }
110
111    string getJavaHome() {
112        return javaHome;
113    }
114
115    string getExecutable() {
116        string exec = "";
117        exec.append( javaHome );
118        exec.append( "\\bin\\java.exe" );
119        return exec;
120    }
121
122    string getVersion() {
123        stringstream ss;
124        ss << era << "." << major << "." << minor << "_" << update;
125        return ss.str();
126    }
127   
128    bool check() {
129        return healthy;
130    }
131
132    bool setVersionFromString( string version ) {
133        era = atoi( version.substr(0,1).c_str() );
134        major = atoi( version.substr(2,1).c_str() );
135        minor = atoi( version.substr(4,1).c_str() );
136        update = atoi( version.substr(6,2).c_str() );
137        return true;
138    }
139   
140    int compare( Jvm otherJvm ) {
141        //era
142        if ( era > otherJvm.getEra() )
143            return 1;
144        else if ( era < otherJvm.getEra() )
145            return -1;
146       
147        //major
148        if ( major > otherJvm.getMajor() )
149            return 1;
150        else if ( major < otherJvm.getMajor() )
151            return -1;
152           
153        //minor
154        if ( minor > otherJvm.getMinor() )
155            return 1;
156        else if ( minor < otherJvm.getMinor() )
157            return -1;
158
159        //update
160        if ( update > otherJvm.getUpdate() )
161            return 1;
162        else if ( update < otherJvm.getUpdate() )
163            return -1;
164
165        //all the same so far, must be exactly the same
166        return 0;
167
168    }
169   
170    int getEra() { return era; }
171    int getMajor() { return major; }
172    int getMinor() { return minor; }
173    int getUpdate() { return update; }
174   
175    private:
176   
177    void setVersionFromExeOuput() {
178        string command = "", output = "";
179        command.append( "\"" );
180        command.append( getExecutable() );
181        command.append( "\"" );
182        command.append(" -version 2>&1");
183        int result = process( command, output );
184        if ( result == 0 ) {
185            if ( _stricmp( output.substr( 0, 12 ).c_str() , "java version" ) == 0 || true ) {
186                era = atoi( output.substr(14,1).c_str() );
187                major = atoi( output.substr(16,1).c_str() );
188                minor = atoi( output.substr(18,1).c_str() );
189                update = atoi( output.substr(20,2).c_str() );
190                //if ( verbose) cout << "set version to: " << era << "." << major << "." << minor << "_" << update << endl;
191            } else {
192                healthy=false;
193            }
194        } else {
195            healthy = false;
196        }
197    }
198   
199   
200};
201
202string actionToString( Action a ) {
203    if ( a == Find )
204        return "Find";
205    else if ( a == Launch )
206        return "Launch";
207    else if ( a == Compare )
208        return "Compare";
209    return "Unknown";
210}
211
212string jvmPropertyToString( JvmProperty jp ) {
213    if ( jp == JavaHome )
214        return "JavaHome";
215    else if ( jp == Version )
216        return "Version";
217    else if ( jp == Executable )
218        return "Executable";
219    return "Unknown";
220}
221
222void usage() {
223   
224    cout
225        << "-----------------" << endl
226        << " search4j: usage" << endl
227        << "-----------------" << endl
228        << "Three usage methods: find, compare and launch" << endl
229        << endl
230        << "find:     find java and print out information about it" << endl
231        << endl
232        << "          search4j [-v|-e] [-m VERSION_STRING]" << endl
233        << "          eg: search4j -m 1.4.1_01 -e" << endl
234        << endl
235        << "          by default, print JAVA_HOME. E.g., C:\\Program Files\\jre1.5.0_15, or" << endl
236        << "          if -v is specified, print the java version string. E.g. 1.5.0_15, or" << endl
237        << "          if -e is specified, print the path the to the java executable. E.g. C:\\Program Files\\jre1.5.0_15\\bin\\java.exe" << endl
238        << "          if -m option is used, find a java of the given version or newer, or fail" << endl
239        << endl
240        << "compare:  compare the found java with the given java version string" << endl
241        << endl
242        << "          search4j -c VERSION_STRING" << endl
243        << "          eg: search4j -c VERSION_STRING" << endl
244        << endl
245        << "          print -1 if found java is older" << endl
246        << "          print 0 if found java is same" << endl
247        << "          print 1 if found java is newer" << endl
248        << endl
249        << "launch:   launch the given executable jar with the found java" << endl
250        << endl
251        << "          search4j -l EXECUTABLE_JAR [-m VERSION_STRING]" << endl
252        << "          eg: search4j -l greenstone3.jar" << endl
253        << endl
254        << "          specify the location of the jar relative to the current directory" << endl
255        << "          if -m option is used, find a java of the given version or newer" << endl
256        << endl
257        << "Global Options:" << endl
258        << "          --verbose : have search4j print out information about what its doing" << endl
259        << "          --help : display this usage screen" << endl
260        << endl
261        ;
262}
263
264//another global
265Jvm minimum;
266
267
268void regSearch(HKEY hKey, const char* keyName, int searchType) {
269    DWORD x = 0;
270    unsigned long size = 1024;
271    FILETIME time;
272    char buffer[1024] = {0};
273    while (RegEnumKeyEx(
274                hKey,           // handle to key to enumerate
275                x++,            // index of subkey to enumerate
276                buffer,         // address of buffer for subkey name
277                &size,          // address for size of subkey buffer
278                NULL,           // reserved
279                NULL,           // address of buffer for class string
280                NULL,           // address for size of class buffer
281                &time) == ERROR_SUCCESS) {
282        strcpy(foundJavaVer, buffer);
283        foundJava = searchType;
284        size = 1024;
285    }
286}
287
288
289/*
290* function to find java
291* implements the logic drawn on the dl lab whiteboard in feb 08
292* return a Jvm object which represents the jvm on disk
293*/
294bool find( Jvm &jvm ) {
295   
296    if ( verbose ) cout << "Searching for a JVM" << endl;
297    char *javaHome = "";
298    bool jvmFound = false;
299   
300    if ( !jvmFound ) {
301        //try JAVA_HOME
302        if ( verbose ) cout << " - trying JAVA_HOME: ";
303        javaHome = getenv( "JAVA_HOME" );
304        if ( javaHome != NULL ) {
305            jvm.setJavaHome( javaHome );
306            if ( jvm.check() ) {
307                if ( use_minimum ) {
308                    if ( jvm.compare( minimum ) >= 0 ) {
309                        jvmFound = true;
310                    }
311                } else {
312                    jvmFound = true;
313                }
314            }
315        }
316        if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
317    }
318   
319    if ( !jvmFound ) {
320        //try JRE_HOME
321        if ( verbose ) cout << " - trying JRE_HOME: ";
322        javaHome = getenv( "JRE_HOME" );
323        if ( javaHome != NULL ) {
324            jvm.setJavaHome( javaHome );
325            if ( jvm.check() ) {
326                if ( use_minimum ) {
327                    if ( jvm.compare( minimum ) >= 0 ) {
328                        jvmFound = true;
329                    }
330                } else {
331                    jvmFound = true;
332                }
333            }
334        }
335        if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
336    }
337   
338    if ( !jvmFound ) {
339        //try the registry - this code based on launch4j code
340        if ( verbose ) cout << " - trying the registry: ";
341        HKEY hKey;
342        const char jre[] = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
343        const char sdk[] = "SOFTWARE\\JavaSoft\\Java Development Kit";
344       
345        if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(jre), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS ) {
346            regSearch(hKey, jre, FOUND_JRE);
347            RegCloseKey(hKey);
348        }
349       
350        if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(sdk), 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS ) {
351            regSearch(hKey, sdk, FOUND_SDK);
352            RegCloseKey(hKey);
353        }
354       
355        if ( foundJava != NO_JAVA_FOUND ) {
356            char path[1024] = {0};
357            char keyBuffer[1024];
358            unsigned long datatype;
359            unsigned long bufferlength = 1024;
360            if (foundJava == FOUND_JRE) {
361                strcpy(keyBuffer, jre);
362            } else {
363                strcpy(keyBuffer, sdk);
364            }
365            strcat(keyBuffer, "\\");
366            strcat(keyBuffer, foundJavaVer);
367            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(keyBuffer), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
368                unsigned char buffer[1024] = {0};
369                if (RegQueryValueEx(hKey, "JavaHome", NULL, &datatype, buffer, &bufferlength) == ERROR_SUCCESS) {
370                    int i = 0;
371                    do {
372                        path[i] = buffer[i];
373                    } while (path[i++] != 0);
374                    if (foundJava == FOUND_SDK) {
375                        strcat(path, "\\jre");
376                    }
377                    jvm.setJavaHome( path );
378                    if ( jvm.check() ) {
379                        if ( use_minimum ) {
380                            if ( jvm.compare( minimum ) >= 0 ) {
381                                jvmFound = true;
382                            }
383                        } else {
384                            jvmFound = true;
385                        }
386                    }
387                }
388                RegCloseKey(hKey);
389            }
390        }
391        if ( verbose ) { if( jvmFound ) cout << "yes" << endl; else cout << "no" << endl; }
392    }
393
394    return jvmFound;
395}
396
397int main ( int argc, char** argv ) {
398    //cout << "testing process()" << endl;
399    //string out = "";
400    //process( "dir", out );
401    //cout << out << endl;
402    //return 0;
403
404
405    JvmProperty jvmProperty = JavaHome;
406    Action action = Find;
407    string arg1 = "";
408   
409    //parse commandline arguments
410    for (int i=1; i<argc; i++) {
411        if ( _stricmp(argv[i], "--verbose") == 0 ) {
412            verbose = true;
413        } else if ( _stricmp(argv[i], "--help") == 0 || _stricmp(argv[i], "--usage") == 0 ) {
414            usage();
415            return 0;
416        } else if ( _stricmp(argv[i], "-v") == 0 ) {
417            jvmProperty = Version;
418        } else if ( _stricmp(argv[i], "-e") == 0 ) {
419            jvmProperty = Executable;
420        } else if ( _stricmp(argv[i], "-c") == 0 ) {
421            action = Compare;
422            if ( i == argc-1 ) {
423                usage();
424                return 0;
425            } else {
426                arg1 = argv[++i];
427            }
428
429            } else if ( _stricmp(argv[i], "-m") == 0 ) {
430            if ( i == argc-1 ) {
431                usage();
432                return 0;
433            } else {
434                if ( !minimum.setVersionFromString( argv[++i] ) ) {
435                    usage();
436                    return 0;
437                }
438                use_minimum = true;
439            }
440
441        } else if ( _stricmp(argv[i], "-l") == 0 ) {
442            action = Launch;
443            arg1 = argv[++i];
444
445        } else {
446            cout << "unknown option: " << argv[i] << endl;
447            return -1;
448        }
449    }
450   
451    //summarise commandline arguments
452    if ( verbose ) {
453        cout << "Action: " << actionToString( action ) << endl;
454    }
455
456    //find java
457    Jvm foundJvm;
458    bool found = find( foundJvm );
459
460    //check if it was found
461    if ( found ) {
462        if ( verbose ) cout << "Found JVM at '" << foundJvm.getJavaHome() << "'" << endl;
463    } else {
464        //not found - exit with -1
465        if ( verbose ) cout << "JVM not found" << endl;
466        return -1;
467    }
468
469
470    //Find Action
471    //---------------
472    if ( action == Find ) {
473
474        if ( verbose ) cout << "Property to print: " << jvmPropertyToString( jvmProperty ) << endl;     
475
476        //found - print out info about it
477        if ( jvmProperty == JavaHome ) {
478            cout << foundJvm.getJavaHome() << endl;
479        } else if ( jvmProperty == Version ) {
480            cout << foundJvm.getVersion() << endl;
481        } else if ( jvmProperty == Executable ) {
482            cout << foundJvm.getExecutable() << endl;
483        } else {
484            return -1; //should never happen
485        }
486           
487
488    //Compare Action
489    //---------------
490    } else if ( action == Compare ) {
491       
492        if ( verbose ) cout << "Compare to java at: " << arg1 << endl;
493
494        //load a dummy jvm for comparison
495        Jvm givenJvm;
496        if ( !givenJvm.setVersionFromString(arg1) ) {
497            if ( verbose ) cout << "Could not parse that version string" << endl;
498            return -1;
499        }
500       
501        //compare
502        cout << foundJvm.compare( givenJvm );
503        return 0;
504
505       
506    //Launch Action
507    //---------------
508    } else if ( action == Launch ) {
509
510        if ( verbose ) cout << "Jar to launch: " << arg1 << endl;
511       
512        string cmd = "\"", output = "";
513        cmd.append( foundJvm.getExecutable() );
514        cmd.append( "\" -jar " );
515        cmd.append( arg1 );
516       
517        process( cmd, output );
518       
519    }
520   
521    return 0;
522}
Note: See TracBrowser for help on using the browser.