You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2011/06/21 08:30:24 UTC

svn commit: r1137871 - in /commons/proper/daemon/trunk: ./ src/native/windows/apps/prunsrv/ src/native/windows/include/ src/native/windows/src/ src/site/xdoc/

Author: mturk
Date: Tue Jun 21 06:30:23 2011
New Revision: 1137871

URL: http://svn.apache.org/viewvc?rev=1137871&view=rev
Log:
DAEMON-209: Add --LibraryPath option

Modified:
    commons/proper/daemon/trunk/RELEASE-NOTES.txt
    commons/proper/daemon/trunk/src/native/windows/apps/prunsrv/prunsrv.c
    commons/proper/daemon/trunk/src/native/windows/include/apxwin.h
    commons/proper/daemon/trunk/src/native/windows/include/javajni.h
    commons/proper/daemon/trunk/src/native/windows/src/javajni.c
    commons/proper/daemon/trunk/src/native/windows/src/private.h
    commons/proper/daemon/trunk/src/native/windows/src/utils.c
    commons/proper/daemon/trunk/src/site/xdoc/procrun.xml

Modified: commons/proper/daemon/trunk/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/RELEASE-NOTES.txt?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/RELEASE-NOTES.txt (original)
+++ commons/proper/daemon/trunk/RELEASE-NOTES.txt Tue Jun 21 06:30:23 2011
@@ -31,6 +31,8 @@ Commons DAEMON 1.0.3 requires a minimum 
 
 NEW FEATURES:
 
+* DAEMON-209: Add --LibraryPath to procrun for setting the
+              LoadLibrary serch paths (1.0.6)
 * DAEMON-208: Add -server and -client -jvm <name> synonyms (1.0.6)
 * DAEMON-205: Add support for building on ARM processors (1.0.6)
 * DAEMON-204: Add DaemonSignal interface that allows catching SIGUSR2

Modified: commons/proper/daemon/trunk/src/native/windows/apps/prunsrv/prunsrv.c
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/windows/apps/prunsrv/prunsrv.c?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/native/windows/apps/prunsrv/prunsrv.c (original)
+++ commons/proper/daemon/trunk/src/native/windows/apps/prunsrv/prunsrv.c Tue Jun 21 06:30:23 2011
@@ -99,37 +99,38 @@ static APXCMDLINEOPT _options[] = {
 /* 8  */    { L"Environment",       L"Environment",     NULL,           APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
 /* 9  */    { L"User",              L"User",            NULL,           APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
 /* 10 */    { L"Password",          L"Password",        NULL,           APXCMDOPT_BIN | APXCMDOPT_REG, NULL, 0},
+/* 11 */    { L"LibraryPath",       L"LibraryPath",     NULL,           APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
 
-/* 11 */    { L"JavaHome",          L"JavaHome",        L"Java",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 12 */    { L"Jvm",               L"Jvm",             L"Java",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 13 */    { L"JvmOptions",        L"Options",         L"Java",        APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
-/* 14 */    { L"Classpath",         L"Classpath",       L"Java",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 15 */    { L"JvmMs",             L"JvmMs",           L"Java",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
-/* 16 */    { L"JvmMx",             L"JvmMx",           L"Java",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
-/* 17 */    { L"JvmSs",             L"JvmSs",           L"Java",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
-
-/* 18 */    { L"StopImage",         L"Image",           L"Stop",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 19 */    { L"StopPath",          L"WorkingPath",     L"Stop",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 20 */    { L"StopClass",         L"Class",           L"Stop",        APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 21 */    { L"StopParams",        L"Params",          L"Stop",        APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
-/* 22 */    { L"StopMethod",        L"Method",          L"Stop",        APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 23 */    { L"StopMode",          L"Mode",            L"Stop",        APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 24 */    { L"StopTimeout",       L"Timeout",         L"Stop",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
-
-/* 25 */    { L"StartImage",        L"Image",           L"Start",       APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 26 */    { L"StartPath",         L"WorkingPath",     L"Start",       APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 27 */    { L"StartClass",        L"Class",           L"Start",       APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 28 */    { L"StartParams",       L"Params",          L"Start",       APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
-/* 29 */    { L"StartMethod",       L"Method",          L"Start",       APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 30 */    { L"StartMode",         L"Mode",            L"Start",       APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-
-/* 31 */    { L"LogPath",           L"Path",            L"Log",         APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 32 */    { L"LogPrefix",         L"Prefix",          L"Log",         APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 33 */    { L"LogLevel",          L"Level",           L"Log",         APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
-/* 34 */    { L"StdError",          L"StdError",        L"Log",         APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 35 */    { L"StdOutput",         L"StdOutput",       L"Log",         APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
-/* 36 */    { L"LogJniMessages",    L"LogJniMessages",  L"Log",         APXCMDOPT_INT | APXCMDOPT_REG, NULL, 1},
-/* 37 */    { L"PidFile",           L"PidFile",         L"Log",         APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 12 */    { L"JavaHome",          L"JavaHome",        L"Java",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 13 */    { L"Jvm",               L"Jvm",             L"Java",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 14 */    { L"JvmOptions",        L"Options",         L"Java",        APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
+/* 15 */    { L"Classpath",         L"Classpath",       L"Java",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 16 */    { L"JvmMs",             L"JvmMs",           L"Java",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
+/* 17 */    { L"JvmMx",             L"JvmMx",           L"Java",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
+/* 19 */    { L"JvmSs",             L"JvmSs",           L"Java",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
+
+/* 19 */    { L"StopImage",         L"Image",           L"Stop",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 20 */    { L"StopPath",          L"WorkingPath",     L"Stop",        APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 21 */    { L"StopClass",         L"Class",           L"Stop",        APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 22 */    { L"StopParams",        L"Params",          L"Stop",        APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
+/* 23 */    { L"StopMethod",        L"Method",          L"Stop",        APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 24 */    { L"StopMode",          L"Mode",            L"Stop",        APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 25 */    { L"StopTimeout",       L"Timeout",         L"Stop",        APXCMDOPT_INT | APXCMDOPT_REG, NULL, 0},
+
+/* 26 */    { L"StartImage",        L"Image",           L"Start",       APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 27 */    { L"StartPath",         L"WorkingPath",     L"Start",       APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 28 */    { L"StartClass",        L"Class",           L"Start",       APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 29 */    { L"StartParams",       L"Params",          L"Start",       APXCMDOPT_MSZ | APXCMDOPT_REG, NULL, 0},
+/* 30 */    { L"StartMethod",       L"Method",          L"Start",       APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 31 */    { L"StartMode",         L"Mode",            L"Start",       APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+
+/* 32 */    { L"LogPath",           L"Path",            L"Log",         APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 33 */    { L"LogPrefix",         L"Prefix",          L"Log",         APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 34 */    { L"LogLevel",          L"Level",           L"Log",         APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
+/* 35 */    { L"StdError",          L"StdError",        L"Log",         APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 36 */    { L"StdOutput",         L"StdOutput",       L"Log",         APXCMDOPT_STE | APXCMDOPT_REG, NULL, 0},
+/* 37 */    { L"LogJniMessages",    L"LogJniMessages",  L"Log",         APXCMDOPT_INT | APXCMDOPT_REG, NULL, 1},
+/* 38 */    { L"PidFile",           L"PidFile",         L"Log",         APXCMDOPT_STR | APXCMDOPT_REG, NULL, 0},
             /* NULL terminate the array */
             { NULL }
 };
@@ -159,38 +160,39 @@ static APXCMDLINEOPT _options[] = {
 
 #define SO_USER             GET_OPT_V(9)
 #define SO_PASSWORD         GET_OPT_V(10)
+#define SO_LIBPATH          GET_OPT_V(11)
 
-#define SO_JAVAHOME         GET_OPT_V(11)
-#define SO_JVM              GET_OPT_V(12)
-#define SO_JVMOPTIONS       GET_OPT_V(13)
-#define SO_CLASSPATH        GET_OPT_V(14)
-#define SO_JVMMS            GET_OPT_I(15)
-#define SO_JVMMX            GET_OPT_I(16)
-#define SO_JVMSS            GET_OPT_I(17)
-
-#define SO_STOPIMAGE        GET_OPT_V(18)
-#define SO_STOPPATH         GET_OPT_V(19)
-#define SO_STOPCLASS        GET_OPT_V(20)
-#define SO_STOPPARAMS       GET_OPT_V(21)
-#define SO_STOPMETHOD       GET_OPT_V(22)
-#define SO_STOPMODE         GET_OPT_V(23)
-#define SO_STOPTIMEOUT      GET_OPT_I(24)
-
-#define SO_STARTIMAGE       GET_OPT_V(25)
-#define SO_STARTPATH        GET_OPT_V(26)
-#define SO_STARTCLASS       GET_OPT_V(27)
-#define SO_STARTPARAMS      GET_OPT_V(28)
-#define SO_STARTMETHOD      GET_OPT_V(29)
-#define SO_STARTMODE        GET_OPT_V(30)
-
-#define SO_LOGPATH          GET_OPT_V(31)
-#define SO_LOGPREFIX        GET_OPT_V(32)
-#define SO_LOGLEVEL         GET_OPT_V(33)
-
-#define SO_STDERROR         GET_OPT_V(34)
-#define SO_STDOUTPUT        GET_OPT_V(35)
-#define SO_JNIVFPRINTF      GET_OPT_I(36)
-#define SO_PIDFILE          GET_OPT_V(37)
+#define SO_JAVAHOME         GET_OPT_V(12)
+#define SO_JVM              GET_OPT_V(13)
+#define SO_JVMOPTIONS       GET_OPT_V(14)
+#define SO_CLASSPATH        GET_OPT_V(15)
+#define SO_JVMMS            GET_OPT_I(16)
+#define SO_JVMMX            GET_OPT_I(17)
+#define SO_JVMSS            GET_OPT_I(18)
+
+#define SO_STOPIMAGE        GET_OPT_V(19)
+#define SO_STOPPATH         GET_OPT_V(20)
+#define SO_STOPCLASS        GET_OPT_V(21)
+#define SO_STOPPARAMS       GET_OPT_V(22)
+#define SO_STOPMETHOD       GET_OPT_V(23)
+#define SO_STOPMODE         GET_OPT_V(24)
+#define SO_STOPTIMEOUT      GET_OPT_I(25)
+
+#define SO_STARTIMAGE       GET_OPT_V(26)
+#define SO_STARTPATH        GET_OPT_V(27)
+#define SO_STARTCLASS       GET_OPT_V(28)
+#define SO_STARTPARAMS      GET_OPT_V(29)
+#define SO_STARTMETHOD      GET_OPT_V(30)
+#define SO_STARTMODE        GET_OPT_V(31)
+
+#define SO_LOGPATH          GET_OPT_V(32)
+#define SO_LOGPREFIX        GET_OPT_V(33)
+#define SO_LOGLEVEL         GET_OPT_V(34)
+
+#define SO_STDERROR         GET_OPT_V(35)
+#define SO_STDOUTPUT        GET_OPT_V(36)
+#define SO_JNIVFPRINTF      GET_OPT_I(37)
+#define SO_PIDFILE          GET_OPT_V(38)
 
 /* Main service table entry
  * filled at run-time
@@ -835,7 +837,7 @@ static DWORD WINAPI serviceStop(LPVOID l
             /* If the Working path is specified change the current directory
              * but only if the start path wasn't specified already.
              */
-            SetCurrentDirectoryW(SO_STARTPATH);
+            SetCurrentDirectoryW(SO_STOPPATH);
         }
         hWorker = apxCreateJava(gPool, _jni_jvmpath);
         if (IS_INVALID_HANDLE(hWorker)) {
@@ -854,6 +856,7 @@ static DWORD WINAPI serviceStop(LPVOID l
         gSargs.lpArguments      = _jni_sparam;
         gSargs.szStdErrFilename = NULL;
         gSargs.szStdOutFilename = NULL;
+        gSargs.szLibraryPath    = SO_LIBPATH;
 
         if (lstrcmpA(_jni_sclass, "java/lang/System") == 0)
             _onexit(onExitHook);
@@ -1030,6 +1033,10 @@ static DWORD serviceStart()
             /* If the Working path is specified change the current directory */
             SetCurrentDirectoryW(SO_STARTPATH);
         }
+        if (lstrlenW(SO_LIBPATH) > 0) {
+            /* Add LibraryPath to the PATH */
+           apxAddEnvironmentVariableW(gPool, L"PATH", SO_LIBPATH);
+        }
         /* Set the environment using putenv, so JVM can use it */
         setInprocEnvironment();
         /* Create the JVM glbal worker */
@@ -1050,6 +1057,7 @@ static DWORD serviceStart()
         gRargs.lpArguments      = _jni_rparam;
         gRargs.szStdErrFilename = gStdwrap.szStdErrFilename;
         gRargs.szStdOutFilename = gStdwrap.szStdOutFilename;
+        gRargs.szLibraryPath    = SO_LIBPATH;
 
         if (!apxJavaStart(&gRargs)) {
             rv = 4;
@@ -1066,6 +1074,10 @@ static DWORD serviceStart()
                                 _service_name ? _service_name : L"unknown");
             return 1;
         }
+        if (lstrlenW(SO_LIBPATH) > 0) {
+            /* Add LibraryPath to the PATH */
+           apxAddEnvironmentVariableW(gPool, L"PATH", SO_LIBPATH);
+        }
         /* Redirect process */
         gWorker = apxCreateProcessW(gPool,
                                     0,

Modified: commons/proper/daemon/trunk/src/native/windows/include/apxwin.h
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/windows/include/apxwin.h?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/native/windows/include/apxwin.h (original)
+++ commons/proper/daemon/trunk/src/native/windows/include/apxwin.h Tue Jun 21 06:30:23 2011
@@ -187,6 +187,7 @@ LPSTR           apxExpandStrA(APXHANDLE 
 LPWSTR          apxExpandStrW(APXHANDLE hPool, LPCWSTR szString);
 void            apxStrCharReplaceA(LPSTR szString, CHAR chReplace, CHAR chReplaceWith);
 void            apxStrCharReplaceW(LPWSTR szString, WCHAR chReplace, WCHAR chReplaceWith);
+BOOL            apxAddEnvironmentVariableW(APXHANDLE hPool, LPCWSTR wsName, LPCWSTR szAdd);
 
 
 LPVOID  AplFillMemory(PVOID Destination, SIZE_T Length, BYTE Fill);

Modified: commons/proper/daemon/trunk/src/native/windows/include/javajni.h
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/windows/include/javajni.h?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/native/windows/include/javajni.h (original)
+++ commons/proper/daemon/trunk/src/native/windows/include/javajni.h Tue Jun 21 06:30:23 2011
@@ -36,6 +36,7 @@ typedef struct stAPXJAVA_THREADARGS
     BOOL        setErrorOrOut;
     LPCWSTR     szStdErrFilename;
     LPCWSTR     szStdOutFilename;
+    LPCWSTR     szLibraryPath;
 } APXJAVA_THREADARGS, *LPAPXJAVA_THREADARGS;
 
 APXHANDLE   apxCreateJava(APXHANDLE hPool, LPCWSTR szJvmDllPath);

Modified: commons/proper/daemon/trunk/src/native/windows/src/javajni.c
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/windows/src/javajni.c?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/native/windows/src/javajni.c (original)
+++ commons/proper/daemon/trunk/src/native/windows/src/javajni.c Tue Jun 21 06:30:23 2011
@@ -872,7 +872,12 @@ static DWORD WINAPI __apxJavaWorkerThrea
                            pArgs->bJniVfprintf)) {
         WORKER_EXIT(2);
     }
-
+    if (pArgs->szLibraryPath && *pArgs->szLibraryPath) {
+        DYNLOAD_FPTR_ADDRESS(SetDllDirectoryW, KERNEL32);
+        DYNLOAD_CALL(SetDllDirectoryW)(pArgs->szLibraryPath);
+        apxLogWrite(APXLOG_MARK_DEBUG "DLL search path set to '%S'",
+                    pArgs->szLibraryPath);
+    }
     if (!apxJavaLoadMainClass(pArgs->hJava,
                               pArgs->szClassName,
                               pArgs->szMethodName,

Modified: commons/proper/daemon/trunk/src/native/windows/src/private.h
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/windows/src/private.h?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/native/windows/src/private.h (original)
+++ commons/proper/daemon/trunk/src/native/windows/src/private.h Tue Jun 21 06:30:23 2011
@@ -265,5 +265,4 @@ DWORD   __apxGetMultiSzLengthW(LPCWSTR l
 LPSTR   __apxGetEnvironmentVariableA(APXHANDLE hPool, LPCSTR szName);
 LPWSTR  __apxGetEnvironmentVariableW(APXHANDLE hPool, LPCWSTR wsName);
 
-
 #endif /* _PRIVATE_H_INCLUDED_ */

Modified: commons/proper/daemon/trunk/src/native/windows/src/utils.c
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/native/windows/src/utils.c?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/native/windows/src/utils.c (original)
+++ commons/proper/daemon/trunk/src/native/windows/src/utils.c Tue Jun 21 06:30:23 2011
@@ -107,6 +107,29 @@ LPSTR __apxGetEnvironmentVariableA(APXHA
     return szRet;
 }
 
+BOOL apxAddEnvironmentVariableW(APXHANDLE hPool, LPCWSTR wsName, LPCWSTR szAdd)
+{
+    LPWSTR wsAdd;
+    DWORD  rc;
+    DWORD  al;
+    
+    rc = GetEnvironmentVariableW(wsName, NULL, 0);
+    if (rc == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+        return FALSE;
+    al = lstrlenW(szAdd) + 1;    
+    if (!(wsAdd = apxPoolAlloc(hPool, (al + rc + 1) * sizeof(WCHAR))))
+        return FALSE;
+    lstrcpyW(wsAdd, szAdd);        
+    lstrcatW(wsAdd, L";");        
+    if (!GetEnvironmentVariableW(wsName, wsAdd + al, rc)) {
+        apxLogWrite(APXLOG_MARK_SYSERR);
+        apxFree(wsAdd);
+        return FALSE;
+    }
+    SetEnvironmentVariableW(wsName, wsAdd);
+    apxFree(wsAdd);
+    return TRUE;
+}
 
 LPWSTR AsciiToWide(LPCSTR s, LPWSTR ws)
 {

Modified: commons/proper/daemon/trunk/src/site/xdoc/procrun.xml
URL: http://svn.apache.org/viewvc/commons/proper/daemon/trunk/src/site/xdoc/procrun.xml?rev=1137871&r1=1137870&r2=1137871&view=diff
==============================================================================
--- commons/proper/daemon/trunk/src/site/xdoc/procrun.xml (original)
+++ commons/proper/daemon/trunk/src/site/xdoc/procrun.xml Tue Jun 21 06:30:23 2011
@@ -254,6 +254,14 @@ then it is treated the same as <b>--</b>
     <td>Password for user account set by --ServiceUser parameter</td>
     </tr>
     <tr>
+    <td>--LibraryPath</td>
+    <td></td>
+    <td>Directory added to the search path used to locate the DLLs for the JVM.
+        This directory is added both in front of the <b>PATH</b> environment variable
+        and as a parameter to the <b>SetDLLDirectory</b> function.
+    </td>
+    </tr>
+    <tr>
     <td>--JavaHome</td>
     <td>JAVA_HOME</td>
     <td>Set a different JAVA_HOME than defined by JAVA_HOME environment