1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
21 #include <config_folders.h>
25 #include "osl/process.h"
26 #include "osl/security.hxx"
27 #include "osl/file.hxx"
28 #include "osl/module.hxx"
29 #include <osl/diagnose.h>
30 #include <osl/getglobalmutex.hxx>
31 #include "rtl/byteseq.hxx"
32 #include "rtl/ustrbuf.hxx"
33 #include "rtl/instance.hxx"
34 #include "salhelper/linkhelper.hxx"
35 #include "salhelper/thread.hxx"
36 #include "boost/noncopyable.hpp"
37 #include "boost/scoped_array.hpp"
38 #include "com/sun/star/uno/Sequence.hxx"
45 #pragma warning(push, 1)
55 #include "vendorlist.hxx"
56 #include "diagnostics.h"
61 using ::rtl::Reference
;
64 #define HKEY_SUN_JRE L"Software\\JavaSoft\\Java Runtime Environment"
65 #define HKEY_SUN_SDK L"Software\\JavaSoft\\Java Development Kit"
69 #if !(defined MACOSX && defined X86_64)
71 char const *g_arJavaNames
[] = {
82 /* These are directory names which could contain multiple java installations.
84 char const *g_arCollectDirs
[] = {
86 #ifndef JVM_ONE_PATH_CHECK
97 /* These are directories in which a java installation is
100 char const *g_arSearchPaths
[] = {
103 "Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin",
104 "System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/"
106 #ifndef JVM_ONE_PATH_CHECK
110 "usr/local/IBMJava2-ppc-142",
111 "usr/local/j2sdk1.3.1",
128 extern VendorSupportMapEntry gVendorMap
[];
131 bool getSDKInfoFromRegistry(vector
<OUString
> & vecHome
);
132 bool getJREInfoFromRegistry(vector
<OUString
>& vecJavaHome
);
135 bool decodeOutput(const OString
& s
, OUString
* out
);
143 rtl::Reference
<VendorBase
> const & info
,
144 std::vector
<rtl::Reference
<VendorBase
>> & infos
)
148 infos
.begin(), infos
.end(), InfoFindSame(info
->getHome())));
149 if (i
== infos
.end()) {
150 infos
.push_back(info
);
157 bool getAndAddJREInfoByPath(
158 const OUString
& path
,
159 std::vector
<rtl::Reference
<VendorBase
> > & allInfos
,
160 std::vector
<rtl::Reference
<VendorBase
> > & addedInfos
)
162 rtl::Reference
<VendorBase
> aInfo
= getJREInfoByPath(path
);
164 if (addJREInfo(aInfo
, allInfos
)) {
165 addedInfos
.push_back(aInfo
);
173 OUString
getLibraryLocation()
175 OUString libraryFileUrl
;
176 OSL_VERIFY(osl::Module::getUrlFromAddress(reinterpret_cast<void *>(getLibraryLocation
), libraryFileUrl
));
177 return getDirFromFile(libraryFileUrl
);
182 rtl::Bootstrap
* operator()(const OUString
& sIni
)
184 static rtl::Bootstrap
aInstance(sIni
);
190 struct InitBootstrapData
192 OUString
const & operator()()
194 static OUString sIni
;
195 OUStringBuffer
buf( 255);
196 buf
.append( getLibraryLocation());
198 buf
.appendAscii( "/../" LIBO_ETC_FOLDER
);
200 buf
.appendAscii( SAL_CONFIGFILE("/sunjavaplugin") );
201 sIni
= buf
.makeStringAndClear();
202 JFW_TRACE2("Using configuration file " << sIni
);
208 rtl::Bootstrap
* getBootstrap()
210 return rtl_Instance
< rtl::Bootstrap
, InitBootstrap
,
211 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
212 OUString
, InitBootstrapData
>::create(
213 InitBootstrap(), ::osl::GetGlobalMutex(), InitBootstrapData());
219 class FileHandleGuard
: private boost::noncopyable
222 inline FileHandleGuard(oslFileHandle
& rHandle
):
223 m_rHandle(rHandle
) {}
225 inline ~FileHandleGuard();
227 inline oslFileHandle
& getHandle() { return m_rHandle
; }
230 oslFileHandle
& m_rHandle
;
233 inline FileHandleGuard::~FileHandleGuard()
237 if (osl_closeFile(m_rHandle
) != osl_File_E_None
)
239 OSL_FAIL("unexpected situation");
245 class FileHandleReader
255 inline FileHandleReader(oslFileHandle
& rHandle
):
256 m_aGuard(rHandle
), m_nSize(0), m_nIndex(0), m_bLf(false) {}
258 Result
readLine(OString
* pLine
);
261 enum { BUFFER_SIZE
= 1024 };
263 sal_Char m_aBuffer
[BUFFER_SIZE
];
264 FileHandleGuard m_aGuard
;
270 FileHandleReader::Result
271 FileHandleReader::readLine(OString
* pLine
)
273 OSL_ENSURE(pLine
, "specification violation");
275 for (bool bEof
= true;; bEof
= false)
277 if (m_nIndex
== m_nSize
)
279 sal_uInt64 nRead
= 0;
280 switch (osl_readFile(
281 m_aGuard
.getHandle(), m_aBuffer
, sizeof(m_aBuffer
), &nRead
))
283 case osl_File_E_PIPE
: //HACK! for windows
286 case osl_File_E_None
:
290 return bEof
? RESULT_EOF
: RESULT_OK
;
293 m_nSize
= static_cast< int >(nRead
);
295 case osl_File_E_INTR
:
303 if (m_bLf
&& m_aBuffer
[m_nIndex
] == 0x0A)
307 int nStart
= m_nIndex
;
308 while (m_nIndex
!= m_nSize
)
309 switch (m_aBuffer
[m_nIndex
++])
314 *pLine
+= OString(m_aBuffer
+ nStart
,
315 m_nIndex
- 1 - nStart
);
316 //TODO! check for overflow, and not very efficient
320 *pLine
+= OString(m_aBuffer
+ nStart
, m_nIndex
- nStart
);
321 //TODO! check for overflow, and not very efficient
325 class AsynchReader
: public salhelper::Thread
328 boost::scoped_array
<sal_Char
> m_arData
;
332 FileHandleGuard m_aGuard
;
334 virtual ~AsynchReader() {}
336 void execute() SAL_OVERRIDE
;
339 AsynchReader(oslFileHandle
& rHandle
);
341 /** only call this function after this thread has finished.
343 That is, call join on this instance and then call getData.
349 AsynchReader::AsynchReader(oslFileHandle
& rHandle
):
350 Thread("jvmfwkAsyncReader"), m_nDataSize(0), m_bError(false),
351 m_bDone(false), m_aGuard(rHandle
)
355 OString
AsynchReader::getData()
357 return OString(m_arData
.get(), m_nDataSize
);
360 void AsynchReader::execute()
362 const sal_uInt64 BUFFER_SIZE
= 4096;
363 sal_Char aBuffer
[BUFFER_SIZE
];
367 //the function blocks until something could be read or the pipe closed.
368 switch (osl_readFile(
369 m_aGuard
.getHandle(), aBuffer
, BUFFER_SIZE
, &nRead
))
371 case osl_File_E_PIPE
: //HACK! for windows
373 case osl_File_E_None
:
385 else if (nRead
<= BUFFER_SIZE
)
387 //Save the data we have in m_arData into a temporary array
388 boost::scoped_array
<sal_Char
> arTmp( new sal_Char
[m_nDataSize
]);
389 memcpy(arTmp
.get(), m_arData
.get(), m_nDataSize
);
390 //Enlarge m_arData to hold the newly read data
391 m_arData
.reset(new sal_Char
[(size_t)(m_nDataSize
+ nRead
)]);
392 //Copy back the data that was already in m_arData
393 memcpy(m_arData
.get(), arTmp
.get(), m_nDataSize
);
394 //Add the newly read data to m_arData
395 memcpy(m_arData
.get() + m_nDataSize
, aBuffer
, (size_t) nRead
);
396 m_nDataSize
+= (size_t) nRead
;
401 static bool isEnvVarSetToOne(const OUString
&aVar
)
404 getBootstrap()->getFrom(aVar
, aValue
);
405 return aValue
== "1";
408 bool getJavaProps(const OUString
& exePath
,
409 #ifdef JVM_ONE_PATH_CHECK
410 const OUString
& homePath
,
412 std::vector
<std::pair
<OUString
, OUString
> >& props
,
417 OSL_ASSERT(!exePath
.isEmpty());
419 //We need to set the CLASSPATH in case the office is started from
420 //a different directory. The JREProperties.class is expected to reside
421 //next to the plugin, except on OS X where it is in ../Resources/java relative
424 if (osl_getModuleURLFromAddress(reinterpret_cast<void *>(&getJavaProps
),
425 & sThisLib
.pData
) == sal_False
)
429 sThisLib
= getDirFromFile(sThisLib
);
431 if (osl_getSystemPathFromFileURL(sThisLib
.pData
, & sClassPath
.pData
)
438 if (sClassPath
.endsWith("/"))
439 sClassPath
+= "../Resources/java/";
441 sClassPath
+= "/../Resources/java";
444 //check if we shall examine a Java for accessibility support
445 //If the bootstrap variable is "1" then we pass the argument
446 //"noaccessibility" to JREProperties.class. This will prevent
447 //that it calls java.awt.Toolkit.getDefaultToolkit();
448 bool bNoAccessibility
= isEnvVarSetToOne("JFW_PLUGIN_DO_NOT_CHECK_ACCESSIBILITY");
450 //prepare the arguments
452 OUString arg1
= "-classpath";// + sClassPath;
453 OUString arg2
= sClassPath
;
454 OUString
arg3("JREProperties");
455 OUString arg4
= "noaccessibility";
456 rtl_uString
*args
[4] = {arg1
.pData
, arg2
.pData
, arg3
.pData
};
459 // Java is no longer required for a11y - we use atk directly.
460 bNoAccessibility
= !isEnvVarSetToOne("JFW_PLUGIN_FORCE_ACCESSIBILITY");
463 // Only add the fourth param if the bootstrap parameter is set.
464 if (bNoAccessibility
)
466 args
[3] = arg4
.pData
;
470 oslProcess javaProcess
= 0;
471 oslFileHandle fileOut
= 0;
472 oslFileHandle fileErr
= 0;
474 FileHandleReader
stdoutReader(fileOut
);
475 rtl::Reference
< AsynchReader
> stderrReader(new AsynchReader(fileErr
));
477 JFW_TRACE2("Executing: " + exePath
);
478 oslProcessError procErr
=
479 osl_executeProcess_WithRedirectedIO( exePath
.pData
,//usExe.pData,
481 cArgs
, //sal_uInt32 nArguments,
482 osl_Process_HIDDEN
, //oslProcessOption Options,
483 NULL
, //oslSecurity Security,
484 usStartDir
.pData
,//usStartDir.pData,//usWorkDir.pData, //rtl_uString *strWorkDir,
485 NULL
, //rtl_uString *strEnvironment[],
486 0, // sal_uInt32 nEnvironmentVars,
487 &javaProcess
, //oslProcess *pProcess,
488 NULL
,//oslFileHandle *pChildInputWrite,
489 &fileOut
,//oslFileHandle *pChildOutputRead,
490 &fileErr
);//oslFileHandle *pChildErrorRead);
492 if( procErr
!= osl_Process_E_None
)
494 JFW_TRACE2("Execution failed");
495 *bProcessRun
= false;
497 "osl_executeProcess failed (" << ret
<< "): \"" << exePath
<< "\"");
502 JFW_TRACE2("Java executed successfully");
506 //Start asynchronous reading (different thread) of error stream
507 stderrReader
->launch();
509 //Use this thread to read output stream
510 FileHandleReader::Result rs
= FileHandleReader::RESULT_OK
;
514 rs
= stdoutReader
.readLine( & aLine
);
515 if (rs
!= FileHandleReader::RESULT_OK
)
518 if (!decodeOutput(aLine
, &sLine
))
520 JFW_TRACE2(" \"" << sLine
<< " \"");
521 sLine
= sLine
.trim();
524 //The JREProperties class writes key value pairs, separated by '='
525 sal_Int32 index
= sLine
.indexOf('=', 0);
526 OSL_ASSERT(index
!= -1);
527 OUString sKey
= sLine
.copy(0, index
);
528 OUString sVal
= sLine
.copy(index
+ 1);
530 #ifdef JVM_ONE_PATH_CHECK
531 //replace absolute path by linux distro link
532 OUString
sHomeProperty("java.home");
533 if(sHomeProperty
.equals(sKey
))
535 sVal
= homePath
+ "/jre";
539 props
.push_back(std::make_pair(sKey
, sVal
));
542 if (rs
!= FileHandleReader::RESULT_ERROR
&& !props
.empty())
545 //process error stream data
546 stderrReader
->join();
547 JFW_TRACE2("Java wrote to stderr:\" "
548 << stderrReader
->getData().getStr() << " \"");
550 TimeValue waitMax
= {5 ,0};
551 procErr
= osl_joinProcessWithTimeout(javaProcess
, &waitMax
);
552 OSL_ASSERT(procErr
== osl_Process_E_None
);
553 osl_freeProcessHandle(javaProcess
);
557 /* converts the properties printed by JREProperties.class into
558 readable strings. The strings are encoded as integer values separated
561 bool decodeOutput(const OString
& s
, OUString
* out
)
563 OSL_ASSERT(out
!= 0);
564 OUStringBuffer
buff(512);
565 sal_Int32 nIndex
= 0;
568 OString aToken
= s
.getToken( 0, ' ', nIndex
);
569 if (!aToken
.isEmpty())
571 for (sal_Int32 i
= 0; i
< aToken
.getLength(); ++i
)
573 if (aToken
[i
] < '0' || aToken
[i
] > '9')
576 sal_Unicode value
= (sal_Unicode
)(aToken
.toInt32());
579 } while (nIndex
>= 0);
581 *out
= buff
.makeStringAndClear();
587 void addJavaInfoFromWinReg(
588 std::vector
<rtl::Reference
<VendorBase
> > & allInfos
,
589 std::vector
<rtl::Reference
<VendorBase
> > & addedInfos
)
591 // Get Java s from registry
592 std::vector
<OUString
> vecJavaHome
;
593 if(getSDKInfoFromRegistry(vecJavaHome
))
595 // create impl objects
596 typedef std::vector
<OUString
>::iterator ItHome
;
597 for(ItHome it_home
= vecJavaHome
.begin(); it_home
!= vecJavaHome
.end();
600 getAndAddJREInfoByPath(*it_home
, allInfos
, addedInfos
);
605 if(getJREInfoFromRegistry(vecJavaHome
))
607 typedef std::vector
<OUString
>::iterator ItHome
;
608 for(ItHome it_home
= vecJavaHome
.begin(); it_home
!= vecJavaHome
.end();
611 getAndAddJREInfoByPath(*it_home
, allInfos
, addedInfos
);
617 bool getJavaInfoFromRegistry(const wchar_t* szRegKey
,
618 vector
<OUString
>& vecJavaHome
)
621 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, szRegKey
, 0, KEY_ENUMERATE_SUB_KEYS
, &hRoot
)
625 const DWORD BUFFSIZE
= 1024;
626 wchar_t bufVersion
[BUFFSIZE
];
627 DWORD nNameLen
= BUFFSIZE
;
629 nNameLen
= sizeof(bufVersion
);
631 // Iterate over all subkeys of HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment
632 while (RegEnumKeyExW(hRoot
, dwIndex
, bufVersion
, &nNameLen
, NULL
, NULL
, NULL
, &fileTime
) != ERROR_NO_MORE_ITEMS
)
635 // Open a Java Runtime Environment sub key, e.g. "1.4.0"
636 if (RegOpenKeyExW(hRoot
, bufVersion
, 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
639 DWORD dwTmpPathLen
= 0;
640 // Get the path to the JavaHome every JRE entry
641 // Find out how long the string for JavaHome is and allocate memory to hold the path
642 if( RegQueryValueExW(hKey
, L
"JavaHome", 0, &dwType
, NULL
, &dwTmpPathLen
)== ERROR_SUCCESS
)
644 char* szTmpPath
= (char *) malloc( dwTmpPathLen
);
645 // Get the path for the runtime lib
646 if(RegQueryValueExW(hKey
, L
"JavaHome", 0, &dwType
, (unsigned char*) szTmpPath
, &dwTmpPathLen
) == ERROR_SUCCESS
)
648 // There can be several version entries referring with the same JavaHome,e.g 1.4 and 1.4.1
649 OUString
usHome((sal_Unicode
*) szTmpPath
);
650 // check if there is already an entry with the same JavaHomeruntime lib
651 // if so, we use the one with the more accurate version
654 if (osl_getFileURLFromSystemPath(usHome
.pData
, & usHomeUrl
.pData
) ==
657 //iterate over the vector with java home strings
658 typedef vector
<OUString
>::iterator ItHome
;
659 for(ItHome itHome
= vecJavaHome
.begin();
660 itHome
!= vecJavaHome
.end(); ++itHome
)
662 if(usHomeUrl
.equals(*itHome
))
671 vecJavaHome
.push_back(usHomeUrl
);
689 bool getSDKInfoFromRegistry(vector
<OUString
> & vecHome
)
691 return getJavaInfoFromRegistry(HKEY_SUN_SDK
, vecHome
);
694 bool getJREInfoFromRegistry(vector
<OUString
>& vecJavaHome
)
696 return getJavaInfoFromRegistry(HKEY_SUN_JRE
, vecJavaHome
);
701 void bubbleSortVersion(vector
<rtl::Reference
<VendorBase
> >& vec
)
705 int size
= vec
.size() - 1;
708 for(int i
= 0; i
< size
; i
++)
710 for(int j
= size
; j
> 0 + cIter
; j
--)
712 rtl::Reference
<VendorBase
>& cur
= vec
.at(j
);
713 rtl::Reference
<VendorBase
>& next
= vec
.at(j
-1);
716 // comparing invalid SunVersion s is possible, they will be less than a
719 //check if version of current is recognized, by comparing it with itself
722 (void)cur
->compareVersions(cur
->getVersion());
724 catch (MalformedVersionException
&)
726 nCmp
= -1; // current < next
728 //The version of cur is valid, now compare with the second version
733 nCmp
= cur
->compareVersions(next
->getVersion());
735 catch (MalformedVersionException
& )
737 //The second version is invalid, therefore it regards less.
741 if(nCmp
== 1) // cur > next
743 rtl::Reference
<VendorBase
> less
= next
;
753 void addJREInfoFromBinPath(
754 const OUString
& path
, vector
<rtl::Reference
<VendorBase
>> & allInfos
,
755 std::vector
<rtl::Reference
<VendorBase
>> & addedInfos
)
757 // file:///c:/jre/bin
758 //map: jre/bin/java.exe
760 for ( sal_Int32 pos
= 0;
761 gVendorMap
[pos
].sVendorName
!= NULL
; ++pos
)
763 vector
<OUString
> vecPaths
;
764 getJavaExePaths_func pFunc
= gVendorMap
[pos
].getJavaFunc
;
767 char const* const* arExePaths
= (*pFunc
)(&size
);
768 vecPaths
= getVectorFromCharArray(arExePaths
, size
);
770 //make sure argument path does not end with '/'
771 OUString sBinPath
= path
;
772 if (path
.endsWith("/"))
773 sBinPath
= path
.copy(0, path
.getLength() - 1);
775 typedef vector
<OUString
>::const_iterator c_it
;
776 for (c_it i
= vecPaths
.begin(); i
!= vecPaths
.end(); ++i
)
778 //the map contains e.g. jre/bin/java.exe
779 //get the directory where the executable is contained
781 sal_Int32 index
= i
->lastIndexOf('/');
784 //map contained only : "java.exe, then the argument
785 //path is already the home directory
790 // jre/bin/jre -> jre/bin
791 OUString
sMapPath(i
->getStr(), index
);
792 index
= sBinPath
.lastIndexOf(sMapPath
);
794 && (index
+ sMapPath
.getLength() == sBinPath
.getLength())
795 && sBinPath
[index
- 1] == '/')
797 sHome
= sBinPath
.copy(index
- 1);
801 && getAndAddJREInfoByPath(path
, allInfos
, addedInfos
))
809 vector
<Reference
<VendorBase
> > addAllJREInfos(
810 bool checkJavaHomeAndPath
,
811 std::vector
<rtl::Reference
<VendorBase
>> & allInfos
)
813 vector
<Reference
<VendorBase
> > addedInfos
;
816 // Get Javas from the registry
817 addJavaInfoFromWinReg(allInfos
, addedInfos
);
820 if (checkJavaHomeAndPath
) {
821 addJavaInfoFromJavaHome(allInfos
, addedInfos
);
822 //this function should be called after addJavaInfosDirScan.
823 //Otherwise in SDKs Java may be started twice
824 addJavaInfosFromPath(allInfos
, addedInfos
);
828 addJavaInfosDirScan(allInfos
, addedInfos
);
831 bubbleSortVersion(addedInfos
);
836 vector
<OUString
> getVectorFromCharArray(char const * const * ar
, int size
)
838 vector
<OUString
> vec
;
839 for( int i
= 0; i
< size
; i
++)
841 OUString
s(ar
[i
], strlen(ar
[i
]), RTL_TEXTENCODING_UTF8
);
847 /** Checks if the path is a directory. Links are resolved.
848 In case of an error the returned string has the length 0.
849 Otherwise the returned string is the "resolved" file URL.
851 OUString
resolveDirPath(const OUString
& path
)
854 salhelper::LinkResolver
aResolver(osl_FileStatus_Mask_Type
|
855 osl_FileStatus_Mask_FileURL
);
856 if (aResolver
.fetchFileStatus(path
) == osl::FileBase::E_None
)
858 //check if this is a directory
859 if (aResolver
.m_aStatus
.getFileType() == FileStatus::Directory
)
861 #ifndef JVM_ONE_PATH_CHECK
862 ret
= aResolver
.m_aStatus
.getFileURL();
870 /** Checks if the path is a file. If it is a link to a file than
873 OUString
resolveFilePath(const OUString
& path
)
876 salhelper::LinkResolver
aResolver(osl_FileStatus_Mask_Type
|
877 osl_FileStatus_Mask_FileURL
);
878 if (aResolver
.fetchFileStatus(path
) == osl::FileBase::E_None
)
880 //check if this is a file
881 if (aResolver
.m_aStatus
.getFileType() == FileStatus::Regular
)
883 #ifndef JVM_ONE_PATH_CHECK
884 ret
= aResolver
.m_aStatus
.getFileURL();
893 rtl::Reference
<VendorBase
> getJREInfoByPath(
894 const OUString
& path
)
896 rtl::Reference
<VendorBase
> ret
;
897 static vector
<OUString
> vecBadPaths
;
899 static map
<OUString
, rtl::Reference
<VendorBase
> > mapJREs
;
900 typedef map
<OUString
, rtl::Reference
<VendorBase
> >::const_iterator MapIt
;
901 typedef map
<OUString
, rtl::Reference
<VendorBase
> > MAPJRE
;
903 typedef vector
<OUString
>::const_iterator cit_path
;
904 vector
<pair
<OUString
, OUString
> > props
;
906 OUString sResolvedDir
= resolveDirPath(path
);
907 // If this path is invalid then there is no chance to find a JRE here
908 if (sResolvedDir
.isEmpty())
913 //check if the directory path is good, that is a JRE was already recognized.
914 //Then we need not detect it again
915 //For example, a sun JKD contains <jdk>/bin/java and <jdk>/jre/bin/java.
916 //When <jdk>/bin/java has been found then we need not find <jdk>/jre/bin/java.
917 //Otherwise we would execute java two times for evers JDK found.
918 MapIt entry2
= find_if(mapJREs
.begin(), mapJREs
.end(),
919 SameOrSubDirJREMap(sResolvedDir
));
920 if (entry2
!= mapJREs
.end())
922 JFW_TRACE2("JRE found again (detected before): " << sResolvedDir
);
923 return entry2
->second
;
926 for ( sal_Int32 pos
= 0;
927 gVendorMap
[pos
].sVendorName
!= NULL
; ++pos
)
929 vector
<OUString
> vecPaths
;
930 getJavaExePaths_func pFunc
= gVendorMap
[pos
].getJavaFunc
;
933 char const* const* arExePaths
= (*pFunc
)(&size
);
934 vecPaths
= getVectorFromCharArray(arExePaths
, size
);
937 typedef vector
<OUString
>::const_iterator c_it
;
938 for (c_it i
= vecPaths
.begin(); i
!= vecPaths
.end(); ++i
)
940 //if the path is a link, then resolve it
941 //check if the executable exists at all
943 //path can be only "file:///". Then do not append a '/'
944 //sizeof counts the terminating 0
946 if (path
.getLength() == sizeof("file:///") - 1)
947 sFullPath
= sResolvedDir
+ (*i
);
949 sFullPath
= sResolvedDir
+ "/" + (*i
);
951 sFilePath
= resolveFilePath(sFullPath
);
953 if (sFilePath
.isEmpty())
955 //The file path (to java exe) is not valid
956 cit_path ifull
= find(vecBadPaths
.begin(), vecBadPaths
.end(), sFullPath
);
957 if (ifull
== vecBadPaths
.end())
959 vecBadPaths
.push_back(sFullPath
);
964 cit_path ifile
= find(vecBadPaths
.begin(), vecBadPaths
.end(), sFilePath
);
965 if (ifile
!= vecBadPaths
.end())
970 MapIt entry
= mapJREs
.find(sFilePath
);
971 if (entry
!= mapJREs
.end())
973 JFW_TRACE2("JRE found again (detected before): " << sFilePath
);
975 return entry
->second
;
978 bool bProcessRun
= false;
979 if (!getJavaProps(sFilePath
,
980 #ifdef JVM_ONE_PATH_CHECK
983 props
, & bProcessRun
))
985 //The java executable could not be run or the system properties
986 //could not be retrieved. We can assume that this java is corrupt.
987 vecBadPaths
.push_back(sFilePath
);
988 //If there was a java executable, that could be run but we did not get
989 //the system properties, then we also assume that the whole Java installation
990 //does not work. In a jdk there are two executables. One in jdk/bin and the other
991 //in jdk/jre/bin. We do not search any further, because we assume that if one java
992 //does not work then the other does not work as well. This saves us to run java
993 //again which is quite costly.
996 // 1.3.1 special treatment: jdk/bin/java and /jdk/jre/bin/java are links to
997 //a script, named .java_wrapper. The script starts jdk/bin/sparc/native_threads/java
998 //or jdk/jre/bin/sparc/native_threads/java. The script uses the name with which it was
999 //invoked to build the path to the executable. It we start the script directy as .java_wrapper
1000 //then it tries to start a jdk/.../native_threads/.java_wrapper. Therefore the link, which
1001 //is named java, must be used to start the script.
1002 getJavaProps(sFullPath
,
1003 #ifdef JVM_ONE_PATH_CHECK
1006 props
, & bProcessRun
);
1007 // Either we found a working 1.3.1
1008 //Or the java is broken. In both cases we stop searchin under this "root" directory
1012 //sFilePath is no working java executable. We continue with another possible
1019 //sFilePath is a java and we could get the system properties. We proceed with this
1033 return rtl::Reference
<VendorBase
>();
1036 //find java.vendor property
1037 typedef vector
<pair
<OUString
, OUString
> >::const_iterator c_ip
;
1038 OUString
sVendor("java.vendor");
1039 OUString sVendorName
;
1041 for (c_ip i
= props
.begin(); i
!= props
.end(); ++i
)
1043 if (sVendor
.equals(i
->first
))
1045 sVendorName
= i
->second
;
1050 if (!sVendorName
.isEmpty())
1052 //find the creator func for the respective vendor name
1053 for ( sal_Int32 c
= 0;
1054 gVendorMap
[c
].sVendorName
!= NULL
; ++c
)
1056 OUString
sNameMap(gVendorMap
[c
].sVendorName
, strlen(gVendorMap
[c
].sVendorName
),
1057 RTL_TEXTENCODING_ASCII_US
);
1058 if (sNameMap
.equals(sVendorName
))
1060 ret
= createInstance(gVendorMap
[c
].createFunc
, props
);
1067 vecBadPaths
.push_back(sFilePath
);
1071 JFW_TRACE2("Found JRE: " << sResolvedDir
<< " at: " << path
);
1073 mapJREs
.insert(MAPJRE::value_type(sResolvedDir
, ret
));
1074 mapJREs
.insert(MAPJRE::value_type(sFilePath
, ret
));
1080 Reference
<VendorBase
> createInstance(createInstance_func pFunc
,
1081 vector
<pair
<OUString
, OUString
> > properties
)
1084 Reference
<VendorBase
> aBase
= (*pFunc
)();
1087 if (!aBase
->initialize(properties
))
1093 inline OUString
getDirFromFile(const OUString
& usFilePath
)
1095 sal_Int32 index
= usFilePath
.lastIndexOf('/');
1096 return usFilePath
.copy(0, index
);
1099 void addJavaInfosFromPath(
1100 std::vector
<rtl::Reference
<VendorBase
>> & allInfos
,
1101 std::vector
<rtl::Reference
<VendorBase
>> & addedInfos
)
1103 #if !defined JVM_ONE_PATH_CHECK
1104 // Get Java from PATH environment variable
1105 char *szPath
= getenv("PATH");
1108 OUString
usAllPath(szPath
, strlen(szPath
), osl_getThreadTextEncoding());
1109 sal_Int32 nIndex
= 0;
1112 OUString usToken
= usAllPath
.getToken( 0, SAL_PATHSEPARATOR
, nIndex
);
1113 OUString usTokenUrl
;
1114 if(File::getFileURLFromSystemPath(usToken
, usTokenUrl
) == File::E_None
)
1116 if(!usTokenUrl
.isEmpty())
1119 if(usTokenUrl
== ".")
1121 OUString usWorkDirUrl
;
1122 if(osl_Process_E_None
== osl_getProcessWorkingDir(&usWorkDirUrl
.pData
))
1123 usBin
= usWorkDirUrl
;
1125 else if(usTokenUrl
== "..")
1128 if(osl_Process_E_None
== osl_getProcessWorkingDir(&usWorkDir
.pData
))
1129 usBin
= getDirFromFile(usWorkDir
);
1135 if(!usBin
.isEmpty())
1137 addJREInfoFromBinPath(usBin
, allInfos
, addedInfos
);
1142 while ( nIndex
>= 0 );
1148 void addJavaInfoFromJavaHome(
1149 std::vector
<rtl::Reference
<VendorBase
>> & allInfos
,
1150 std::vector
<rtl::Reference
<VendorBase
>> & addedInfos
)
1152 #if !defined JVM_ONE_PATH_CHECK
1153 // Get Java from JAVA_HOME environment
1155 // Note that on OS X is it not normal at all to have a JAVA_HOME environment
1156 // variable. We set it in our build environment for build-time programs, though,
1157 // so it is set when running unit tests that involve Java functionality. (Which affects
1158 // at least CppunitTest_dbaccess_dialog_save, too, and not only the JunitTest ones.)
1159 char *szJavaHome
= getenv("JAVA_HOME");
1162 OUString
sHome(szJavaHome
, strlen(szJavaHome
), osl_getThreadTextEncoding());
1164 if(File::getFileURLFromSystemPath(sHome
, sHomeUrl
) == File::E_None
)
1166 getAndAddJREInfoByPath(sHomeUrl
, allInfos
, addedInfos
);
1172 bool makeDriveLetterSame(OUString
* fileURL
)
1176 if (DirectoryItem::get(*fileURL
, item
) == File::E_None
)
1178 FileStatus
status(osl_FileStatus_Mask_FileURL
);
1179 if (item
.getFileStatus(status
) == File::E_None
)
1181 *fileURL
= status
.getFileURL();
1191 void addJavaInfosDirScan(
1192 std::vector
<rtl::Reference
<VendorBase
>> & allInfos
,
1193 std::vector
<rtl::Reference
<VendorBase
>> & addedInfos
)
1195 JFW_TRACE2("Checking /usr/jdk/latest");
1196 getAndAddJREInfoByPath("file:////usr/jdk/latest", allInfos
, addedInfos
);
1199 #elif defined MACOSX && defined X86_64
1201 void addJavaInfosDirScan(
1202 std::vector
<rtl::Reference
<VendorBase
>> & allInfos
,
1203 std::vector
<rtl::Reference
<VendorBase
>> & addedInfos
)
1206 getAndAddJREInfoByPath("file:///Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home", allInfos
, addedInfos
);
1210 void addJavaInfosDirScan(
1211 std::vector
<rtl::Reference
<VendorBase
>> & allInfos
,
1212 std::vector
<rtl::Reference
<VendorBase
>> & addedInfos
)
1214 OUString excMessage
= "[Java framework] sunjavaplugin: "
1215 "Error in function addJavaInfosDirScan in util.cxx.";
1216 int cJavaNames
= sizeof(g_arJavaNames
) / sizeof(char*);
1217 boost::scoped_array
<OUString
> sarJavaNames(new OUString
[cJavaNames
]);
1218 OUString
*arNames
= sarJavaNames
.get();
1219 for(int i
= 0; i
< cJavaNames
; i
++)
1220 arNames
[i
] = OUString(g_arJavaNames
[i
], strlen(g_arJavaNames
[i
]),
1221 RTL_TEXTENCODING_UTF8
);
1223 int cSearchPaths
= sizeof(g_arSearchPaths
) / sizeof(char*);
1224 boost::scoped_array
<OUString
> sarPathNames(new OUString
[cSearchPaths
]);
1225 OUString
*arPaths
= sarPathNames
.get();
1226 for(int c
= 0; c
< cSearchPaths
; c
++)
1227 arPaths
[c
] = OUString(g_arSearchPaths
[c
], strlen(g_arSearchPaths
[c
]),
1228 RTL_TEXTENCODING_UTF8
);
1230 int cCollectDirs
= sizeof(g_arCollectDirs
) / sizeof(char*);
1231 boost::scoped_array
<OUString
> sarCollectDirs(new OUString
[cCollectDirs
]);
1232 OUString
*arCollectDirs
= sarCollectDirs
.get();
1233 for(int d
= 0; d
< cCollectDirs
; d
++)
1234 arCollectDirs
[d
] = OUString(g_arCollectDirs
[d
], strlen(g_arCollectDirs
[d
]),
1235 RTL_TEXTENCODING_UTF8
);
1239 OUString
usFile("file:///");
1240 for( int ii
= 0; ii
< cSearchPaths
; ii
++)
1242 OUString
usDir1(usFile
+ arPaths
[ii
]);
1244 if(DirectoryItem::get(usDir1
, item
) == File::E_None
)
1246 for(int j
= 0; j
< cCollectDirs
; j
++)
1248 OUString
usDir2(usDir1
+ arCollectDirs
[j
]);
1249 // prevent that we scan the whole /usr, /usr/lib, etc directories
1250 if (!arCollectDirs
[j
].isEmpty())
1253 //Examin every subdirectory
1254 Directory
aCollectionDir(usDir2
);
1256 Directory::RC openErr
= aCollectionDir
.open();
1262 case File::E_NOTDIR
:
1265 JFW_TRACE2("Could not read directory " << usDir2
<< " because of missing access rights");
1268 JFW_TRACE2("Could not read directory " << usDir2
<< ". Osl file error: " << openErr
);
1272 DirectoryItem curIt
;
1273 File::RC errNext
= File::E_None
;
1274 while( (errNext
= aCollectionDir
.getNextItem(curIt
)) == File::E_None
)
1276 FileStatus
aStatus(osl_FileStatus_Mask_FileURL
);
1277 File::RC errStatus
= File::E_None
;
1278 if ((errStatus
= curIt
.getFileStatus(aStatus
)) != File::E_None
)
1280 JFW_TRACE2(excMessage
+ "getFileStatus failed with error " << errStatus
);
1283 JFW_TRACE2("Checking if directory: " << aStatus
.getFileURL() << " is a Java");
1285 getAndAddJREInfoByPath(
1286 aStatus
.getFileURL(), allInfos
, addedInfos
);
1289 JFW_ENSURE(errNext
== File::E_None
|| errNext
== File::E_NOENT
,
1290 "[Java framework] sunjavaplugin: "
1291 "Error while iterating over contens of "
1292 + usDir2
+ ". Osl file error: "
1293 + OUString::number(openErr
));
1298 //When we look directly into a dir like /usr, /usr/lib, etc. then we only
1299 //look for certain java directories, such as jre, jdk, etc. Whe do not want
1300 //to examine the whole directory because of performance reasons.
1301 DirectoryItem item2
;
1302 if(DirectoryItem::get(usDir2
, item2
) == File::E_None
)
1304 for( int k
= 0; k
< cJavaNames
; k
++)
1306 // /usr/java/j2re1.4.0
1307 OUString
usDir3(usDir2
+ arNames
[k
]);
1309 DirectoryItem item3
;
1310 if(DirectoryItem::get(usDir3
, item
) == File::E_None
)
1312 //remove trailing '/'
1313 sal_Int32 islash
= usDir3
.lastIndexOf('/');
1314 if (islash
== usDir3
.getLength() - 1
1316 > RTL_CONSTASCII_LENGTH("file://")))
1317 usDir3
= usDir3
.copy(0, islash
);
1318 getAndAddJREInfoByPath(
1319 usDir3
, allInfos
, addedInfos
);
1328 #endif // ifdef SOLARIS
1332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */