com.quinsoft.zeidon.standardoe.JavaObjectEngine Maven / Gradle / Ivy
/**
Zeidon JOE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zeidon JOE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Zeidon JOE. If not, see .
Copyright 2009-2015 QuinSoft
*/
package com.quinsoft.zeidon.standardoe;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.MapMaker;
import com.quinsoft.zeidon.Application;
import com.quinsoft.zeidon.BrowserStarter;
import com.quinsoft.zeidon.CacheMap;
import com.quinsoft.zeidon.ObjectEngine;
import com.quinsoft.zeidon.ObjectEngineEventListener;
import com.quinsoft.zeidon.Task;
import com.quinsoft.zeidon.UnknownApplicationException;
import com.quinsoft.zeidon.View;
import com.quinsoft.zeidon.ZeidonException;
import com.quinsoft.zeidon.ZeidonLogger;
import com.quinsoft.zeidon.config.HomeDirectory;
import com.quinsoft.zeidon.config.UuidGenerator;
import com.quinsoft.zeidon.config.ZeidonPreferences;
import com.quinsoft.zeidon.config.ZeidonPreferencesFactory;
import com.quinsoft.zeidon.domains.DomainClassLoader;
import com.quinsoft.zeidon.utils.CacheMapImpl;
import com.quinsoft.zeidon.utils.JoeUtils;
/**
*
* This is the standard implementation of the ObjectEngine. The JavaObjectInstance is
* instantiated using a set of options that the engine uses for configuration. Typical
* instantiation:
*
*
*
* JavaOeConfiguration configuration = new DefaultJavaOeConfiguration();
* configuration.set....;
* ObjectEngine oe = new JavaObjectEngine( configuration );
*
*
*/
public class JavaObjectEngine implements ObjectEngine
{
private static final String JOE_VERSION = "1.0";
private static ObjectEngine s_objectEngine = null;
private final ApplicationList applicationList;
private final TaskImpl systemTask;
private final AtomicLong taskCounter = new AtomicLong( 0 );
private final String id;
private final ZeidonPreferencesFactory zeidonPreferencesFactory;
/**
* This is a Concurrent hashmap that can be used by application as an engine-level cache.
*/
private final CacheMap cacheMap = new CacheMapImpl();
/**
* List of tasks. This will be stored in a weak hash map so that if a task is dropped
* it will be automatically removed from this list. We need to keep a taskList that
* is separate from the persistentTaskList because the persistent list is only
* guaranteed to contain user tasks (not the System task).
*
* Key is the task ID.
*/
private final ConcurrentMap taskList;
/**
* This is a list of all persistent tasks. This is a subset of taskList. It's only
* job is to prevent persistent tasks from being cleaned up by the GC. Do not use it
* for any other purpose.
*
* Key is the task ID.
*/
private final ConcurrentMap persistentTaskList;
private final HomeDirectory zeidonHomeDir;
/**
* Every new entity is given a unique key.
*/
private final AtomicLong currentEntityKey = new AtomicLong();
/**
* A listener that gets notified by some events in the Object Engine.
*/
private final ObjectEngineEventListener oeListener;
private final ClassLoader classLoader = JavaObjectEngine.class.getClassLoader();
private final DomainClassLoader domainClassLoader;
private final ExecutorService threadPool;
private final UuidGenerator uuidGenerator;
public final static synchronized ObjectEngine getInstance()
{
if ( s_objectEngine == null )
return getInstance( new DefaultJavaOeConfiguration() );
return s_objectEngine;
}
public final static synchronized ObjectEngine getInstance( DefaultJavaOeConfiguration options )
{
if ( s_objectEngine == null )
s_objectEngine = new JavaObjectEngine( options );
return s_objectEngine;
}
public final static synchronized ObjectEngine getInstance( String preferencesFilename )
{
if ( s_objectEngine == null )
return getInstance( new DefaultJavaOeConfiguration().setPreferencesFilename( preferencesFilename ) );
return s_objectEngine;
}
/**
* Sets the static instance to null to give us a way to create a new JOE instance.
*
* @return
*/
public final static synchronized void resetInstance()
{
s_objectEngine = null;
}
@Override
public String getVersion()
{
// TODO: change this to use the version from Maven.
return JOE_VERSION;
}
/**
* Instantiates a Java Object Engine using the options specified.
*
* @param options
*/
public JavaObjectEngine( JavaOeConfiguration options )
{
ZeidonLogger logger = options.getZeidonLogger();
zeidonHomeDir = options.getHomeDirectory();
domainClassLoader = options.getDomainClassLoader();
threadPool = options.getActivateThreadPool();
zeidonPreferencesFactory = options.getPreferencesFactory();
uuidGenerator = options.getUuidGenerator();
oeListener = options.getObjectEngineListener();
Package _package = this.getClass().getPackage();
String version = _package.getImplementationVersion();
String builtDate = _package.getImplementationTitle();
logger.info( "Zeidon JOE Version: %s Build Date: %s", version, builtDate );
logger.info( "classpath = %s", getClassPath( logger ) );
logger.info( "User.dir = %s", System.getProperty("user.dir") );
// Generate a UUID as a task ID.
id = uuidGenerator.generate().toString();
// Create HashMap with weak values so that tasks will be automatically GC'd when they are no longer being used.
taskList = new MapMaker().concurrencyLevel( 10 ).weakValues().makeMap();
persistentTaskList = options.getPersistentTaskCacheMap();
applicationList = new ApplicationList( zeidonHomeDir, logger );
systemTask = createTask( ObjectEngine.ZEIDON_SYSTEM_APP_NAME, true, ObjectEngine.ZEIDON_SYSTEM_APP_NAME );
oeListener.setObjectEngine( this );
// Check to see if we should start the browser.
String startBrowser = JoeUtils.getEnvProperty( "zeidon.start.browser" );
if ( StringUtils.isBlank( startBrowser ) )
startBrowser = systemTask.readZeidonConfig( "Browser", "Start", "" );
else
// Log a message in case the ENVVAR overrides the value from zeidon.ini
logger.info( "startBrowser indicator is from zeidon.start.browser: %s", startBrowser );
if ( ! StringUtils.isBlank( startBrowser ) && startBrowser.toUpperCase().startsWith( "Y" ) )
startBrowser();
assert logAssertMessage( systemTask ); // Write a message to the log if assertions are on.
}
private boolean logAssertMessage( TaskImpl systemTask )
{
systemTask.log().warn( "Assertions are *ON*" );
return true;
}
/**
* @param logger
*/
private static String getClassPath( ZeidonLogger logger )
{
try
{
StringBuilder classpath = new StringBuilder();
ClassLoader classLoader = classpath.getClass().getClassLoader();
if ( classLoader == null )
classLoader = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
for ( URL url : urls )
classpath.append( url.getFile() ).append( "\n" );
return classpath.toString();
}
catch( Exception e )
{
if ( logger != null )
logger.error( "Error trying to log classpath", e, (Object[]) null );
return "";
}
}
/**
* Starts the browser. This method is public so that it can be called directly from Eclipse.
*/
@Override
@SuppressWarnings("unchecked") // for classLoader.
public boolean startBrowser()
{
String browserClassName = "com.quinsoft.zeidon.objectbrowser.Starter";
try
{
// Load browser class dynamically so we don't have to have the browser to compile.
ClassLoader classLoader = getClassLoader( browserClassName );
Class starterClass;
starterClass = (Class) classLoader.loadClass( browserClassName );
BrowserStarter starter = starterClass.newInstance();
starter.startBrowser( this );
return true;
}
catch ( Exception e )
{
systemTask.log().error( "Couldn't find browser class %s", e, browserClassName );
return false;
}
}
@Override
public List extends Application> getApplicationList()
{
return applicationList.getList();
}
@Override
public TaskImpl createTask( String applicationName, boolean persistent, String taskId )
{
TaskImpl systemTask = getSystemTask() == null ? new TaskImpl( this ) : getSystemTask();
ApplicationImpl app = applicationList.getApplication( systemTask, applicationName );
long counter = taskCounter.incrementAndGet();
if ( StringUtils.isBlank( taskId ) )
taskId = Long.toString( counter );
if ( taskList.containsKey( taskId ) )
throw new ZeidonException( "Task already exists with specified ID: %s", taskId );
TaskImpl task = new TaskImpl(this, app, taskId );
taskList.put( task.getTaskId(), task );
if ( persistent )
persistentTaskList.put( task.getTaskId(), task );
if ( task.log().isTraceEnabled() )
task.log().trace( "Task list count: %d, Persistent count: %d",
taskList.size(), persistentTaskList.size() );
return task;
}
@Override
public TaskImpl createTask( String applicationName, boolean persistent )
{
return createTask( applicationName, persistent, null );
}
@Override
public TaskImpl createTask( String applicationName )
{
return createTask( applicationName, false, null );
}
@Override
public TaskImpl createTask( String applicationName, String taskId )
{
return createTask( applicationName, true, taskId );
}
@Override
public ApplicationImpl getApplication(String appName) throws UnknownApplicationException
{
return applicationList.getApplication( getSystemTask(), appName );
}
@Override
public TaskImpl getSystemTask()
{
return systemTask;
}
@Override
public List extends Task> getTaskList()
{
// Return a copy of the task list. This way if a task is dropped the copy of the
// task list won't be affected.
ArrayList list = new ArrayList( taskList.values() );
Collections.sort( list );
return list;
}
/**
* Removes the task from the persistent task list.
* @param task
*/
void dropTask( TaskImpl task )
{
taskList.remove( task.getTaskId() );
persistentTaskList.remove( task.getTaskId() );
}
@Override
public TaskImpl getTaskById(String id)
{
// If the persistent cache map has a timeout, we need to do the following persistentTaskList.get
// to reset it so the expired task gets removed from the list.
persistentTaskList.get( id );
return taskList.get( id );
}
@Override
public String getHomeDirectory()
{
return zeidonHomeDir.getHomeDirectory();
}
/**
* Returns a unique long key that can be used to uniquely identify the object
* in the current ObjectEngine.
*
* @return
*/
long getNextObjectKey()
{
return currentEntityKey.incrementAndGet();
}
@Override
public ClassLoader getClassLoader( String className )
{
return classLoader;
}
/* (non-Javadoc)
* @see com.quinsoft.zeidon.ObjectEngine#getDomainClassLoader()
*/
@Override
public DomainClassLoader getDomainClassLoader()
{
return domainClassLoader;
}
@Override
public String getId()
{
return id;
}
UUID generateUuid()
{
UUID uuid = uuidGenerator.generate();
return uuid;
}
public int countAllEntities( View view )
{
ViewImpl v = ((InternalView) view).getViewImpl();
return v.countAllEntities();
}
public ExecutorService getThreadPool()
{
return threadPool;
}
@Override
public ZeidonPreferences getZeidonPreferences( Application app )
{
return zeidonPreferencesFactory.getPreferences( app );
}
ObjectEngineEventListener getOeEventListener()
{
return oeListener;
}
@Override
public CacheMap getCacheMap()
{
return cacheMap;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy