|
@@ -20,6 +20,9 @@
|
|
|
|
|
|
package password.pwm;
|
|
|
|
|
|
+import lombok.Builder;
|
|
|
+import lombok.Singular;
|
|
|
+import lombok.Value;
|
|
|
import password.pwm.config.Configuration;
|
|
|
import password.pwm.error.ErrorInformation;
|
|
|
import password.pwm.error.PwmError;
|
|
@@ -27,41 +30,39 @@ import password.pwm.error.PwmUnrecoverableException;
|
|
|
import password.pwm.http.ContextManager;
|
|
|
import password.pwm.util.java.JavaHelper;
|
|
|
import password.pwm.util.java.JsonUtil;
|
|
|
-import password.pwm.util.java.TimeDuration;
|
|
|
import password.pwm.util.logging.PwmLogger;
|
|
|
|
|
|
import java.io.File;
|
|
|
import java.io.FileInputStream;
|
|
|
-import java.io.IOException;
|
|
|
-import java.io.RandomAccessFile;
|
|
|
-import java.io.StringWriter;
|
|
|
-import java.nio.channels.FileChannel;
|
|
|
-import java.nio.channels.FileLock;
|
|
|
-import java.time.Instant;
|
|
|
import java.util.ArrayList;
|
|
|
-import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.HashSet;
|
|
|
+import java.util.EnumMap;
|
|
|
+import java.util.EnumSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Properties;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
+@Value
|
|
|
+@Builder( toBuilder = true )
|
|
|
public class PwmEnvironment
|
|
|
{
|
|
|
private static final PwmLogger LOGGER = PwmLogger.forClass( PwmEnvironment.class );
|
|
|
|
|
|
- // data elements
|
|
|
- private final PwmApplicationMode applicationMode;
|
|
|
- private final Configuration config;
|
|
|
- private final File applicationPath;
|
|
|
- private final boolean internalRuntimeInstance;
|
|
|
- private final File configurationFile;
|
|
|
- private final ContextManager contextManager;
|
|
|
- private final Collection<ApplicationFlag> flags;
|
|
|
- private final Map<ApplicationParameter, String> parameters;
|
|
|
+ @lombok.Builder.Default
|
|
|
+ private PwmApplicationMode applicationMode = PwmApplicationMode.ERROR;
|
|
|
|
|
|
- private final FileLocker fileLocker;
|
|
|
+ private Configuration config;
|
|
|
+ private File applicationPath;
|
|
|
+ private boolean internalRuntimeInstance;
|
|
|
+ private File configurationFile;
|
|
|
+ private ContextManager contextManager;
|
|
|
+
|
|
|
+ @Singular
|
|
|
+ private Set<ApplicationFlag> flags;
|
|
|
+
|
|
|
+ @Singular
|
|
|
+ private Map<ApplicationParameter, String> parameters;
|
|
|
|
|
|
public enum ApplicationParameter
|
|
|
{
|
|
@@ -143,76 +144,6 @@ public class PwmEnvironment
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @SuppressWarnings( "checkstyle:ParameterNumber" )
|
|
|
- private PwmEnvironment(
|
|
|
- final PwmApplicationMode applicationMode,
|
|
|
- final Configuration config,
|
|
|
- final File applicationPath,
|
|
|
- final boolean internalRuntimeInstance,
|
|
|
- final File configurationFile,
|
|
|
- final ContextManager contextManager,
|
|
|
- final Collection<ApplicationFlag> flags,
|
|
|
- final Map<ApplicationParameter, String> parameters
|
|
|
- )
|
|
|
- {
|
|
|
- this.applicationMode = applicationMode == null ? PwmApplicationMode.ERROR : applicationMode;
|
|
|
- this.config = config;
|
|
|
- this.applicationPath = applicationPath;
|
|
|
- this.internalRuntimeInstance = internalRuntimeInstance;
|
|
|
- this.configurationFile = configurationFile;
|
|
|
- this.contextManager = contextManager;
|
|
|
- this.flags = flags == null ? Collections.emptySet() : Collections.unmodifiableSet( new HashSet<>( flags ) );
|
|
|
- this.parameters = parameters == null ? Collections.emptyMap() : Collections.unmodifiableMap( parameters );
|
|
|
-
|
|
|
- this.fileLocker = new FileLocker();
|
|
|
-
|
|
|
- verify();
|
|
|
- }
|
|
|
-
|
|
|
- public PwmApplicationMode getApplicationMode( )
|
|
|
- {
|
|
|
- return applicationMode;
|
|
|
- }
|
|
|
-
|
|
|
- public Configuration getConfig( )
|
|
|
- {
|
|
|
- return config;
|
|
|
- }
|
|
|
-
|
|
|
- public File getApplicationPath( )
|
|
|
- {
|
|
|
- return applicationPath;
|
|
|
- }
|
|
|
-
|
|
|
- public boolean isInternalRuntimeInstance( )
|
|
|
- {
|
|
|
- return internalRuntimeInstance;
|
|
|
- }
|
|
|
-
|
|
|
- public File getConfigurationFile( )
|
|
|
- {
|
|
|
- return configurationFile;
|
|
|
- }
|
|
|
-
|
|
|
- public ContextManager getContextManager( )
|
|
|
- {
|
|
|
- return contextManager;
|
|
|
- }
|
|
|
-
|
|
|
- public Collection<ApplicationFlag> getFlags( )
|
|
|
- {
|
|
|
- return flags;
|
|
|
- }
|
|
|
-
|
|
|
- public Map<ApplicationParameter, String> getParameters( )
|
|
|
- {
|
|
|
- return parameters;
|
|
|
- }
|
|
|
-
|
|
|
- private void verify( )
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
|
|
|
public void verifyIfApplicationPathIsSetProperly( )
|
|
|
throws PwmUnrecoverableException
|
|
@@ -241,12 +172,12 @@ public class PwmEnvironment
|
|
|
)
|
|
|
throws PwmUnrecoverableException
|
|
|
{
|
|
|
- return new Builder( this )
|
|
|
- .setApplicationMode( PwmApplicationMode.NEW )
|
|
|
- .setInternalRuntimeInstance( true )
|
|
|
- .setConfigurationFile( null )
|
|
|
- .setConfig( configuration )
|
|
|
- .createPwmEnvironment();
|
|
|
+ return this.toBuilder()
|
|
|
+ .applicationMode( PwmApplicationMode.NEW )
|
|
|
+ .internalRuntimeInstance( true )
|
|
|
+ .configurationFile( null )
|
|
|
+ .config( configuration )
|
|
|
+ .build();
|
|
|
}
|
|
|
|
|
|
|
|
@@ -302,14 +233,14 @@ public class PwmEnvironment
|
|
|
|
|
|
public static class ParseHelper
|
|
|
{
|
|
|
- public static Collection<ApplicationFlag> readApplicationFlagsFromSystem( final String contextName )
|
|
|
+ public static Set<ApplicationFlag> readApplicationFlagsFromSystem( final String contextName )
|
|
|
{
|
|
|
final String rawValue = readValueFromSystem( EnvironmentParameter.applicationFlags, contextName );
|
|
|
if ( rawValue != null )
|
|
|
{
|
|
|
return parseApplicationFlagValueParameter( rawValue );
|
|
|
}
|
|
|
- return Collections.emptyList();
|
|
|
+ return Collections.emptySet();
|
|
|
}
|
|
|
|
|
|
public static Map<ApplicationParameter, String> readApplicationParmsFromSystem( final String contextName )
|
|
@@ -347,37 +278,25 @@ public class PwmEnvironment
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- public static Collection<ApplicationFlag> parseApplicationFlagValueParameter( final String input )
|
|
|
+ public static Set<ApplicationFlag> parseApplicationFlagValueParameter( final String input )
|
|
|
{
|
|
|
if ( input == null )
|
|
|
{
|
|
|
- return Collections.emptyList();
|
|
|
+ return Collections.emptySet();
|
|
|
}
|
|
|
|
|
|
try
|
|
|
{
|
|
|
final List<String> jsonValues = JsonUtil.deserializeStringList( input );
|
|
|
- final List<ApplicationFlag> returnFlags = new ArrayList<>();
|
|
|
- for ( final String value : jsonValues )
|
|
|
- {
|
|
|
- final ApplicationFlag flag = ApplicationFlag.forString( value );
|
|
|
- if ( value != null )
|
|
|
- {
|
|
|
- returnFlags.add( flag );
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- LOGGER.warn( () -> "unknown " + EnvironmentParameter.applicationFlags.toString() + " value: " + input );
|
|
|
- }
|
|
|
- }
|
|
|
- return Collections.unmodifiableList( returnFlags );
|
|
|
+ final Set<ApplicationFlag> returnFlags = JavaHelper.readEnumSetFromStringCollection( ApplicationFlag.class, jsonValues );
|
|
|
+ return Collections.unmodifiableSet( returnFlags );
|
|
|
}
|
|
|
catch ( final Exception e )
|
|
|
{
|
|
|
//
|
|
|
}
|
|
|
|
|
|
- final List<ApplicationFlag> returnFlags = new ArrayList<>();
|
|
|
+ final Set<ApplicationFlag> returnFlags = EnumSet.noneOf( ApplicationFlag.class );
|
|
|
for ( final String value : input.split( "," ) )
|
|
|
{
|
|
|
final ApplicationFlag flag = ApplicationFlag.forString( value );
|
|
@@ -413,7 +332,7 @@ public class PwmEnvironment
|
|
|
|
|
|
try
|
|
|
{
|
|
|
- final Map<ApplicationParameter, String> returnParams = new HashMap<>();
|
|
|
+ final Map<ApplicationParameter, String> returnParams = new EnumMap<>( ApplicationParameter.class );
|
|
|
for ( final Object key : propValues.keySet() )
|
|
|
{
|
|
|
|
|
@@ -438,235 +357,14 @@ public class PwmEnvironment
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- public static class Builder
|
|
|
+ public static PwmApplicationMode checkForTrial( final PwmApplicationMode mode )
|
|
|
{
|
|
|
- private PwmApplicationMode applicationMode;
|
|
|
- private Configuration config;
|
|
|
- private File applicationPath;
|
|
|
- private boolean internalRuntimeInstance;
|
|
|
- private File configurationFile;
|
|
|
- private ContextManager contextManager;
|
|
|
- private Collection<ApplicationFlag> flags = new HashSet<>();
|
|
|
- private Map<ApplicationParameter, String> params = new HashMap<>();
|
|
|
-
|
|
|
- public Builder( final PwmEnvironment pwmEnvironment )
|
|
|
- {
|
|
|
- this.applicationMode = pwmEnvironment.applicationMode;
|
|
|
- this.config = pwmEnvironment.config;
|
|
|
- this.applicationPath = pwmEnvironment.applicationPath;
|
|
|
- this.internalRuntimeInstance = pwmEnvironment.internalRuntimeInstance;
|
|
|
- this.configurationFile = pwmEnvironment.configurationFile;
|
|
|
- this.contextManager = pwmEnvironment.contextManager;
|
|
|
- this.flags = pwmEnvironment.flags;
|
|
|
- this.params = pwmEnvironment.parameters;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder( final Configuration config, final File applicationPath )
|
|
|
- {
|
|
|
- this.config = config;
|
|
|
- this.applicationPath = applicationPath;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder setApplicationMode( final PwmApplicationMode applicationMode )
|
|
|
- {
|
|
|
- if ( PwmConstants.TRIAL_MODE && applicationMode == PwmApplicationMode.RUNNING )
|
|
|
- {
|
|
|
- LOGGER.info( () -> "application is in trial mode" );
|
|
|
- this.applicationMode = PwmApplicationMode.CONFIGURATION;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- this.applicationMode = applicationMode;
|
|
|
- }
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder setInternalRuntimeInstance( final boolean internalRuntimeInstance )
|
|
|
+ if ( PwmConstants.TRIAL_MODE && mode == PwmApplicationMode.RUNNING )
|
|
|
{
|
|
|
- this.internalRuntimeInstance = internalRuntimeInstance;
|
|
|
- return this;
|
|
|
+ LOGGER.info( () -> "application is in trial mode" );
|
|
|
+ return PwmApplicationMode.CONFIGURATION;
|
|
|
}
|
|
|
|
|
|
- public Builder setConfigurationFile( final File configurationFile )
|
|
|
- {
|
|
|
- this.configurationFile = configurationFile;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder setContextManager( final ContextManager contextManager )
|
|
|
- {
|
|
|
- this.contextManager = contextManager;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder setFlags( final Collection<ApplicationFlag> flags )
|
|
|
- {
|
|
|
- this.flags.clear();
|
|
|
- if ( flags != null )
|
|
|
- {
|
|
|
- this.flags.addAll( flags );
|
|
|
- }
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder setParams( final Map<ApplicationParameter, String> params )
|
|
|
- {
|
|
|
- this.params.clear();
|
|
|
- if ( params != null )
|
|
|
- {
|
|
|
- this.params.putAll( params );
|
|
|
- }
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public Builder setConfig( final Configuration config )
|
|
|
- {
|
|
|
- this.config = config;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- public PwmEnvironment createPwmEnvironment( )
|
|
|
- {
|
|
|
- return new PwmEnvironment(
|
|
|
- applicationMode,
|
|
|
- config,
|
|
|
- applicationPath,
|
|
|
- internalRuntimeInstance,
|
|
|
- configurationFile,
|
|
|
- contextManager,
|
|
|
- flags,
|
|
|
- params
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void attemptFileLock( )
|
|
|
- {
|
|
|
- fileLocker.attemptFileLock();
|
|
|
- }
|
|
|
-
|
|
|
- public void releaseFileLock( )
|
|
|
- {
|
|
|
- fileLocker.releaseFileLock();
|
|
|
- }
|
|
|
-
|
|
|
- public boolean isFileLocked( )
|
|
|
- {
|
|
|
- return fileLocker.isLocked();
|
|
|
- }
|
|
|
-
|
|
|
- public void waitForFileLock( ) throws PwmUnrecoverableException
|
|
|
- {
|
|
|
- final int maxWaitSeconds = this.getFlags().contains( ApplicationFlag.CommandLineInstance )
|
|
|
- ? 1
|
|
|
- : Integer.parseInt( getConfig().readAppProperty( AppProperty.APPLICATION_FILELOCK_WAIT_SECONDS ) );
|
|
|
- final Instant startTime = Instant.now();
|
|
|
- final TimeDuration attemptInterval = TimeDuration.of( 5021, TimeDuration.Unit.MILLISECONDS );
|
|
|
-
|
|
|
- while ( !this.isFileLocked() && TimeDuration.fromCurrent( startTime ).isShorterThan( maxWaitSeconds, TimeDuration.Unit.SECONDS ) )
|
|
|
- {
|
|
|
- attemptFileLock();
|
|
|
-
|
|
|
- if ( !isFileLocked() )
|
|
|
- {
|
|
|
- LOGGER.debug( () -> "can't establish application file lock after "
|
|
|
- + TimeDuration.fromCurrent( startTime ).asCompactString()
|
|
|
- + ", will retry;" );
|
|
|
- attemptInterval.pause();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ( !isFileLocked() )
|
|
|
- {
|
|
|
- final String errorMsg = "unable to obtain application path file lock";
|
|
|
- final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_STARTUP_ERROR, errorMsg );
|
|
|
- throw new PwmUnrecoverableException( errorInformation );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private class FileLocker
|
|
|
- {
|
|
|
- private FileLock lock;
|
|
|
- private final File lockfile;
|
|
|
-
|
|
|
- FileLocker( )
|
|
|
- {
|
|
|
- final String lockfileName = config.readAppProperty( AppProperty.APPLICATION_FILELOCK_FILENAME );
|
|
|
- lockfile = new File( getApplicationPath(), lockfileName );
|
|
|
- }
|
|
|
-
|
|
|
- private boolean lockingAllowed( )
|
|
|
- {
|
|
|
- return !isInternalRuntimeInstance() && !getFlags().contains( ApplicationFlag.NoFileLock );
|
|
|
- }
|
|
|
-
|
|
|
- public boolean isLocked( )
|
|
|
- {
|
|
|
- return !lockingAllowed() || lock != null && lock.isValid();
|
|
|
- }
|
|
|
-
|
|
|
- public void attemptFileLock( )
|
|
|
- {
|
|
|
- if ( lockingAllowed() && !isLocked() )
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- final RandomAccessFile file = new RandomAccessFile( lockfile, "rw" );
|
|
|
- final FileChannel f = file.getChannel();
|
|
|
- lock = f.tryLock();
|
|
|
- if ( lock != null )
|
|
|
- {
|
|
|
- LOGGER.debug( () -> "obtained file lock on file " + lockfile.getAbsolutePath() + " lock is valid=" + lock.isValid() );
|
|
|
- writeLockFileContents( file );
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- LOGGER.debug( () -> "unable to obtain file lock on file " + lockfile.getAbsolutePath() );
|
|
|
- }
|
|
|
- }
|
|
|
- catch ( final Exception e )
|
|
|
- {
|
|
|
- LOGGER.error( () -> "unable to obtain file lock on file " + lockfile.getAbsolutePath() + " due to error: " + e.getMessage() );
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void writeLockFileContents( final RandomAccessFile file )
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- final Properties props = new Properties();
|
|
|
- props.put( "timestamp", JavaHelper.toIsoDate( Instant.now() ) );
|
|
|
- props.put( "applicationPath", PwmEnvironment.this.getApplicationPath() == null ? "n/a" : PwmEnvironment.this.getApplicationPath().getAbsolutePath() );
|
|
|
- props.put( "configurationFile", PwmEnvironment.this.getConfigurationFile() == null ? "n/a" : PwmEnvironment.this.getConfigurationFile().getAbsolutePath() );
|
|
|
- final String comment = PwmConstants.PWM_APP_NAME + " file lock";
|
|
|
- final StringWriter stringWriter = new StringWriter();
|
|
|
- props.store( stringWriter, comment );
|
|
|
- file.write( stringWriter.getBuffer().toString().getBytes( PwmConstants.DEFAULT_CHARSET ) );
|
|
|
- }
|
|
|
- catch ( final IOException e )
|
|
|
- {
|
|
|
- LOGGER.error( () -> "unable to write contents of application lock file: " + e.getMessage() );
|
|
|
- }
|
|
|
- // do not close FileWriter, otherwise lock is released.
|
|
|
- }
|
|
|
-
|
|
|
- public void releaseFileLock( )
|
|
|
- {
|
|
|
- if ( lock != null && lock.isValid() )
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- lock.release();
|
|
|
- }
|
|
|
- catch ( final IOException e )
|
|
|
- {
|
|
|
- LOGGER.error( () -> "error releasing file lock: " + e.getMessage() );
|
|
|
- }
|
|
|
-
|
|
|
- LOGGER.debug( () -> "released file lock on file " + lockfile.getAbsolutePath() );
|
|
|
- }
|
|
|
- }
|
|
|
+ return mode;
|
|
|
}
|
|
|
}
|