448 lines
14 KiB
Java
448 lines
14 KiB
Java
/*
|
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package li.strolch.agent.api;
|
|
|
|
import static li.strolch.model.Tags.Json.*;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.lang.management.*;
|
|
import java.text.MessageFormat;
|
|
import java.util.Locale;
|
|
import java.util.Properties;
|
|
import java.util.Set;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import com.google.gson.JsonArray;
|
|
import com.google.gson.JsonObject;
|
|
import li.strolch.agent.impl.ComponentContainerImpl;
|
|
import li.strolch.exception.StrolchException;
|
|
import li.strolch.persistence.api.StrolchTransaction;
|
|
import li.strolch.privilege.base.PrivilegeException;
|
|
import li.strolch.privilege.model.Certificate;
|
|
import li.strolch.runtime.configuration.ConfigurationParser;
|
|
import li.strolch.runtime.configuration.RuntimeConfiguration;
|
|
import li.strolch.runtime.configuration.StrolchConfiguration;
|
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
|
import li.strolch.runtime.privilege.PrivilegedRunnable;
|
|
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
|
|
import li.strolch.utils.ExecutorPool;
|
|
import li.strolch.utils.helper.StringHelper;
|
|
import li.strolch.utils.helper.SystemHelper;
|
|
import li.strolch.utils.iso8601.ISO8601;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
|
*/
|
|
public class StrolchAgent {
|
|
|
|
public static final String AGENT_VERSION_PROPERTIES = "/agentVersion.properties"; //$NON-NLS-1$
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(StrolchAgent.class);
|
|
|
|
private final StrolchVersion appVersion;
|
|
|
|
private ComponentContainerImpl container;
|
|
private StrolchConfiguration strolchConfiguration;
|
|
|
|
private ExecutorPool executorPool;
|
|
|
|
private JsonObject systemState;
|
|
private long systemStateUpdateTime;
|
|
|
|
private VersionQueryResult versionQueryResult;
|
|
|
|
public StrolchAgent(StrolchVersion appVersion) {
|
|
this.appVersion = appVersion;
|
|
}
|
|
|
|
/**
|
|
* Return the {@link StrolchConfiguration}
|
|
*
|
|
* @return the {@link StrolchConfiguration}
|
|
*/
|
|
public StrolchConfiguration getStrolchConfiguration() {
|
|
return this.strolchConfiguration;
|
|
}
|
|
|
|
/**
|
|
* Return the container
|
|
*
|
|
* @return the container
|
|
*/
|
|
public ComponentContainer getContainer() {
|
|
return this.container;
|
|
}
|
|
|
|
/**
|
|
* @see ComponentContainer#hasComponent(Class)
|
|
*/
|
|
public boolean hasComponent(Class<?> clazz) {
|
|
return this.container.hasComponent(clazz);
|
|
}
|
|
|
|
/**
|
|
* @see ComponentContainer#getComponent(Class)
|
|
*/
|
|
public <T> T getComponent(Class<T> clazz) throws IllegalArgumentException {
|
|
return this.container.getComponent(clazz);
|
|
}
|
|
|
|
public PrivilegeHandler getPrivilegeHandler() throws IllegalArgumentException {
|
|
return this.container.getPrivilegeHandler();
|
|
}
|
|
|
|
/**
|
|
* @see ComponentContainer#getRealm(String)
|
|
*/
|
|
public StrolchRealm getRealm(String realm) throws StrolchException {
|
|
return getComponent(RealmHandler.class).getRealm(realm);
|
|
}
|
|
|
|
/**
|
|
* @see ComponentContainer#getRealm(Certificate)
|
|
*/
|
|
public StrolchRealm getRealm(Certificate certificate) throws StrolchException {
|
|
return this.container.getRealm(certificate);
|
|
}
|
|
|
|
/**
|
|
* @see StrolchRealm#openTx(Certificate, Class, boolean)
|
|
*/
|
|
public StrolchTransaction openTx(Certificate certificate, Class<?> clazz, boolean readOnly) {
|
|
return this.container.getRealm(certificate).openTx(certificate, clazz, readOnly);
|
|
}
|
|
|
|
/**
|
|
* @see StrolchRealm#openTx(Certificate, String, boolean)
|
|
*/
|
|
public StrolchTransaction openTx(Certificate certificate, String action, boolean readOnly) {
|
|
return this.container.getRealm(certificate).openTx(certificate, action, readOnly);
|
|
}
|
|
|
|
/**
|
|
* @see PrivilegeHandler#runAs(String, PrivilegedRunnable)
|
|
*/
|
|
public void runAs(String systemUser, PrivilegedRunnable runnable) throws PrivilegeException, Exception {
|
|
getPrivilegeHandler().runAs(systemUser, runnable);
|
|
}
|
|
|
|
/**
|
|
* @see PrivilegeHandler#runAsAgent(PrivilegedRunnable)
|
|
*/
|
|
public void runAsAgent(PrivilegedRunnable runnable) throws PrivilegeException, Exception {
|
|
getPrivilegeHandler().runAsAgent(runnable);
|
|
}
|
|
|
|
/**
|
|
* @see PrivilegeHandler#runAsAgentWithResult(PrivilegedRunnableWithResult)
|
|
*/
|
|
public <T> T runAsWithResult(String systemUser, PrivilegedRunnableWithResult<T> runnable)
|
|
throws PrivilegeException, Exception {
|
|
return getPrivilegeHandler().runAsWithResult(systemUser, runnable);
|
|
}
|
|
|
|
/**
|
|
* @see PrivilegeHandler#runAsAgentWithResult(PrivilegedRunnableWithResult)
|
|
*/
|
|
public <T> T runAsAgentWithResult(PrivilegedRunnableWithResult<T> runnable) throws PrivilegeException, Exception {
|
|
return getPrivilegeHandler().runAsAgentWithResult(runnable);
|
|
}
|
|
|
|
/**
|
|
* @return the name of this application as is defined in the configuration
|
|
*/
|
|
public String getApplicationName() {
|
|
return this.strolchConfiguration.getRuntimeConfiguration().getApplicationName();
|
|
}
|
|
|
|
/**
|
|
* @return the currently loaded environment of this application as is defined in the configuration
|
|
*/
|
|
public String getEnvironment() {
|
|
return this.strolchConfiguration.getRuntimeConfiguration().getEnvironment();
|
|
}
|
|
|
|
/**
|
|
* @return the agent's {@link Locale}
|
|
*/
|
|
public Locale getLocale() {
|
|
return this.strolchConfiguration.getRuntimeConfiguration().getLocale();
|
|
}
|
|
|
|
/**
|
|
* @return the agent's time zone
|
|
*/
|
|
public String getTimezone() {
|
|
return this.strolchConfiguration.getRuntimeConfiguration().getTimezone();
|
|
}
|
|
|
|
/**
|
|
* Return the {@link ExecutorService} instantiated for this agent
|
|
*
|
|
* @return the {@link ExecutorService} instantiated for this agent
|
|
*/
|
|
public ExecutorService getExecutor() {
|
|
return getExecutor("Agent");
|
|
}
|
|
|
|
public synchronized ExecutorService getExecutor(String poolName) {
|
|
return this.executorPool.getExecutor(poolName);
|
|
}
|
|
|
|
/**
|
|
* Return the {@link ExecutorService} instantiated for this agent
|
|
*
|
|
* @return the {@link ExecutorService} instantiated for this agent
|
|
*/
|
|
public ExecutorService getSingleThreadExecutor() {
|
|
return getSingleThreadExecutor("Agent");
|
|
}
|
|
|
|
public synchronized ExecutorService getSingleThreadExecutor(String poolName) {
|
|
return this.executorPool.getSingleThreadExecutor(poolName);
|
|
}
|
|
|
|
/**
|
|
* Return the {@link ScheduledExecutorService} instantiated for this agent
|
|
*
|
|
* @return the {@link ScheduledExecutorService} instantiated for this agent
|
|
*/
|
|
public ScheduledExecutorService getScheduledExecutor() {
|
|
return getScheduledExecutor("Agent");
|
|
}
|
|
|
|
public synchronized ScheduledExecutorService getScheduledExecutor(String poolName) {
|
|
return this.executorPool.getScheduledExecutor(poolName);
|
|
}
|
|
|
|
/**
|
|
* Initializes the underlying container and prepares the executor services. Before calling this method,
|
|
* {@link #setup(String, File, File, File)} must have ben called
|
|
*/
|
|
public void initialize() {
|
|
if (this.container == null)
|
|
throw new RuntimeException("Please call setup first!");
|
|
|
|
this.executorPool = new ExecutorPool();
|
|
this.container.initialize();
|
|
}
|
|
|
|
/**
|
|
* Starts the container
|
|
*/
|
|
public void start() {
|
|
if (this.container == null)
|
|
throw new RuntimeException("Please call setup first!");
|
|
this.container.start();
|
|
}
|
|
|
|
/**
|
|
* Stops the container
|
|
*/
|
|
public void stop() {
|
|
if (this.container != null)
|
|
this.container.stop();
|
|
}
|
|
|
|
/**
|
|
* Destroys the container and the executor services
|
|
*/
|
|
public void destroy() {
|
|
|
|
if (this.executorPool != null)
|
|
this.executorPool.destroy();
|
|
|
|
if (this.container != null)
|
|
this.container.destroy();
|
|
this.container = null;
|
|
}
|
|
|
|
/**
|
|
* <p>
|
|
* <b>Note:</b> Use {@link StrolchBootstrapper} instead of calling this method directly!
|
|
* </p>
|
|
*
|
|
* <p>
|
|
* Sets up the agent by parsing the configuration file and initializes the given environment
|
|
* </p>
|
|
*
|
|
* @param environment
|
|
* the current environment
|
|
* @param configPathF
|
|
* the path to the config directory
|
|
* @param dataPathF
|
|
* the path to the data directory
|
|
* @param tempPathF
|
|
* the path to the temp directory
|
|
*/
|
|
void setup(String environment, File configPathF, File dataPathF, File tempPathF) {
|
|
|
|
String msg = "[{0}] Setting up Strolch Container using the following paths:"; //$NON-NLS-1$
|
|
logger.info(MessageFormat.format(msg, environment));
|
|
logger.info(" - Config: " + configPathF.getAbsolutePath());
|
|
logger.info(" - Data: " + dataPathF.getAbsolutePath());
|
|
logger.info(" - Temp: " + tempPathF.getAbsolutePath());
|
|
logger.info(" - user.dir: " + SystemHelper.getUserDir());
|
|
|
|
this.strolchConfiguration = ConfigurationParser.parseConfiguration(environment, configPathF, dataPathF,
|
|
tempPathF);
|
|
|
|
ComponentContainerImpl container = new ComponentContainerImpl(this);
|
|
container.setup(this.strolchConfiguration);
|
|
|
|
this.container = container;
|
|
|
|
RuntimeConfiguration config = this.strolchConfiguration.getRuntimeConfiguration();
|
|
logger.info(MessageFormat.format("Setup Agent {0}:{1}", config.getApplicationName(),
|
|
config.getEnvironment())); //$NON-NLS-1$
|
|
}
|
|
|
|
protected void assertContainerStarted() {
|
|
if (this.container == null || this.container.getState() != ComponentState.STARTED) {
|
|
String msg = "Container is not yet started!"; //$NON-NLS-1$
|
|
throw new IllegalStateException(msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return Returns the pseudo unique Id to be used during object creation from external services.
|
|
*/
|
|
public static synchronized String getUniqueId() {
|
|
return StringHelper.getUniqueId();
|
|
}
|
|
|
|
/**
|
|
* @return Returns the pseudo unique Id to be used during object creation from external services.
|
|
*/
|
|
public static synchronized Long getUniqueIdLong() {
|
|
return StringHelper.getUniqueIdLong();
|
|
}
|
|
|
|
/**
|
|
* Returns the version of this agent
|
|
*
|
|
* @return the version of this agent
|
|
*/
|
|
public VersionQueryResult getVersion() {
|
|
if (this.versionQueryResult == null) {
|
|
|
|
VersionQueryResult queryResult = new VersionQueryResult();
|
|
queryResult.setAppVersion(this.appVersion);
|
|
|
|
Properties properties = new Properties();
|
|
|
|
try (InputStream stream = getClass().getResourceAsStream(AGENT_VERSION_PROPERTIES)) {
|
|
properties.load(stream);
|
|
RuntimeConfiguration runtimeConfiguration = getStrolchConfiguration().getRuntimeConfiguration();
|
|
AgentVersion agentVersion = new AgentVersion(runtimeConfiguration.getApplicationName(),
|
|
runtimeConfiguration.getEnvironment(), runtimeConfiguration.getLocale(),
|
|
runtimeConfiguration.getTimezone(), properties);
|
|
queryResult.setAgentVersion(agentVersion);
|
|
} catch (IOException e) {
|
|
String msg = MessageFormat.format("Failed to read version properties for agent: {0}",
|
|
e.getMessage()); //$NON-NLS-1$
|
|
queryResult.getErrors().add(msg);
|
|
logger.error(msg, e);
|
|
}
|
|
|
|
Set<Class<?>> componentTypes = this.container.getComponentTypes();
|
|
for (Class<?> componentType : componentTypes) {
|
|
StrolchComponent component = (StrolchComponent) this.container.getComponent(componentType);
|
|
try {
|
|
ComponentVersion componentVersion = component.getVersion();
|
|
queryResult.add(componentVersion);
|
|
} catch (Exception e) {
|
|
String msg = "Failed to read version properties for component {0} due to: {1}"; //$NON-NLS-1$
|
|
msg = MessageFormat.format(msg, component.getName(), e.getMessage());
|
|
queryResult.getErrors().add(msg);
|
|
logger.error(msg, e);
|
|
}
|
|
}
|
|
|
|
this.versionQueryResult = queryResult;
|
|
}
|
|
|
|
return this.versionQueryResult;
|
|
}
|
|
|
|
public JsonObject getSystemState(long updateInterval, TimeUnit updateIntervalUnit) {
|
|
|
|
if (this.systemState == null
|
|
|| System.currentTimeMillis() - this.systemStateUpdateTime > updateIntervalUnit.toMillis(
|
|
updateInterval)) {
|
|
this.systemState = new JsonObject();
|
|
|
|
JsonObject osJ = new JsonObject();
|
|
this.systemState.add(OPERATING_SYSTEM, osJ);
|
|
osJ.addProperty(OS_NAME, SystemHelper.osName);
|
|
osJ.addProperty(OS_ARCH, SystemHelper.osArch);
|
|
osJ.addProperty(OS_VERSION, SystemHelper.osVersion);
|
|
osJ.addProperty(JAVA_VENDOR, SystemHelper.javaVendor);
|
|
osJ.addProperty(JAVA_VERSION, SystemHelper.javaVersion);
|
|
|
|
OperatingSystemMXBean osMXBean = ManagementFactory.getOperatingSystemMXBean();
|
|
osJ.addProperty(AVAILABLE_PROCESSORS, osMXBean.getAvailableProcessors());
|
|
osJ.addProperty(SYSTEM_LOAD_AVERAGE, osMXBean.getSystemLoadAverage());
|
|
|
|
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
|
|
osJ.addProperty(START_TIME, ISO8601.toString(runtimeMXBean.getStartTime()));
|
|
osJ.addProperty(UPTIME, runtimeMXBean.getUptime());
|
|
|
|
// memory
|
|
JsonObject memoryJ = new JsonObject();
|
|
this.systemState.add(MEMORY, memoryJ);
|
|
|
|
if (osMXBean instanceof com.sun.management.OperatingSystemMXBean os) {
|
|
memoryJ.addProperty(TOTAL_PHYSICAL_MEMORY_SIZE, os.getTotalMemorySize());
|
|
memoryJ.addProperty(FREE_PHYSICAL_MEMORY_SIZE, os.getFreeMemorySize());
|
|
memoryJ.addProperty(FREE_SWAP_SPACE_SIZE, os.getFreeSwapSpaceSize());
|
|
memoryJ.addProperty(COMMITTED_VIRTUAL_MEMORY_SIZE, os.getCommittedVirtualMemorySize());
|
|
}
|
|
|
|
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
|
|
MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
|
|
memoryJ.addProperty(HEAP_MEMORY_USAGE_INIT, heapMemoryUsage.getInit());
|
|
memoryJ.addProperty(HEAP_MEMORY_USAGE_USED, heapMemoryUsage.getUsed());
|
|
memoryJ.addProperty(HEAP_MEMORY_USAGE_MAX, heapMemoryUsage.getMax());
|
|
memoryJ.addProperty(HEAP_MEMORY_USAGE_COMMITTED, heapMemoryUsage.getCommitted());
|
|
|
|
// disk space
|
|
JsonArray rootsJ = new JsonArray();
|
|
this.systemState.add(ROOTS, rootsJ);
|
|
File[] roots = File.listRoots();
|
|
for (File root : roots) {
|
|
JsonObject rootJ = new JsonObject();
|
|
rootsJ.add(rootJ);
|
|
rootJ.addProperty(PATH, root.getAbsolutePath());
|
|
rootJ.addProperty(USABLE_SPACE, root.getUsableSpace());
|
|
rootJ.addProperty(USED_SPACE, root.getTotalSpace() - root.getFreeSpace());
|
|
rootJ.addProperty(FREE_SPACE, root.getFreeSpace());
|
|
rootJ.addProperty(TOTAL_SPACE, root.getTotalSpace());
|
|
}
|
|
|
|
this.systemStateUpdateTime = System.currentTimeMillis();
|
|
}
|
|
|
|
return this.systemState;
|
|
}
|
|
}
|