package org.groovymud.object.registry;
import groovy.util.GroovyScriptEngine;
import groovy.util.ResourceException;
import groovy.util.ScriptException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.codehaus.groovy.control.CompilationFailedException;
import org.groovymud.object.Container;
import org.groovymud.object.MudObject;
import org.groovymud.object.ObjectLocation;
import org.groovymud.object.alive.Player;
import org.groovymud.object.registry.domain.DomainManager;
import org.groovymud.object.registry.persistence.DataSourceException;
import org.groovymud.object.registry.persistence.MudDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.XStreamException;
/* Copyright 2008 Matthew Corby-Eaglen
*
* 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.
*/
/**
* The MudObjectAttendant is responsible for loading, saving, registering and
* configuring all mud objects in the game.
*
* The object can have an id
*
*/
public class MudObjectAttendant {
private static final String PLAYER_STORE = new String("playerfiles" + File.separator);
private ObjectLocation theVoid;
private ObjectLocation playerImpl;
private static final Logger logger = Logger.getLogger(MudObjectAttendant.class);
private transient MudDataSource<MudObject> persistence;
private transient GroovyScriptEngine groovyScriptEngine;
private transient XStream xstream;
private transient List<DomainManager<MudObject>> domainManagers;
private final Registry objectRegistry;
@Autowired(required = true)
public MudObjectAttendant(Registry reg) {
this.objectRegistry = reg;
}
/**
* gets a list of all object handles registered by any domain managers
* @return
*/
public List<String> getObjectHandles() {
List<String> handles = new ArrayList<String>();
for (DomainManager<MudObject> domainManager : domainManagers) {
handles.addAll(domainManager.getHandles());
}
return handles;
}
public MudObject cloneObject(String handle) throws MudCloneException {
MudObject o = getObjectRegistry().getMudObject(handle);
if (o == null) {
o = loadObject(handle);
}
o = cloneObject(o, true);
getObjectRegistry().register(o, handle);
return o;
}
public MudObject findOrClone(ObjectLocation loc) throws MudCloneException {
MudObject obj = getObjectRegistry().getMudObject(loc.getHandle());
if (obj == null) {
load(loc);
obj = cloneObject(loc.getHandle());
}
return obj;
}
protected MudObject cloneObject(MudObject o, boolean register) throws MudCloneException {
if (o == null) {
throw new IllegalArgumentException("object cannot be null");
}
Exception anException = null;
MudObject copy = null;
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
persistence.serialize(o, out);
InputStream in = new ByteArrayInputStream(out.toByteArray());
copy = persistence.deserializeObject(in);
} catch (XStreamException e) {
anException = e;
logger.error(e, e);
} finally {
if (anException != null) {
throw new MudCloneException("could not clone object", anException);
} else if (register) {
getObjectRegistry().register(copy);
}
}
return copy;
}
/**
* loads a mudobject object and initialise it using a handle
*
* Each domain manager is checked for an instance of the required handle
*
* an instance of that object is loaded from the manager, which may or may not
* be a single instance
*
* @param ObjectLocation
* location - representing where the object can be found in the
* spring container
* @throws MudCloneException
*/
private MudObject loadObject(String handle) throws MudCloneException {
MudObject obj = null;
for (DomainManager<MudObject> domainManager : domainManagers) {
if (domainManager.contains(handle)) {
obj = domainManager.getObject(handle);
break;
}
}
return obj;
}
public void load(ObjectLocation location) {
for (DomainManager<MudObject> domainManager : domainManagers) {
if (domainManager.contains(location.getHandle())) {
break;
} else if (domainManager.canLoad(location.getDefinition())) {
logger.info("loading definition" + location.getDefinition());
domainManager.loadDomain(location.getDefinition());
}
}
}
public Player loadPlayerData(String username) throws CompilationFailedException, ResourceException, ScriptException, DataSourceException {
logger.info("loading playerImpl object..");
Player player = null;
synchronized (this.getClass()) {
load(getPlayerImpl());
player = (Player) persistence.loadObject(PLAYER_STORE + username);
}
return player;
}
public void moveToLocation(MudObject player) throws InstantiationException, FileNotFoundException, CompilationFailedException, MudCloneException {
Container room = null;
logger.info("moving player to location.");
ObjectLocation location = player.getContainerLocation();
room = (Container) getObjectRegistry().getMudObject(location.getHandle());
if (room == null) {
logger.info("loading container..");
load(location);
room = (Container) cloneObject(location.getHandle());
}
if (room == null) {
throw new InstantiationException("container was null!");
}
logger.info("adding player to container");
room.addMudObject(player);
}
public void movePlayerToVoid(Player player) throws IOException, FileNotFoundException {
try {
logger.info("moving player to the void..");
player.setContainerLocation(getTheVoid());
moveToLocation(player);
} catch (CompilationFailedException e) {
logger.error(e, e);
} catch (InstantiationException e) {
logger.error(e, e);
} catch (MudCloneException e) {
logger.error(e, e);
}
}
public Player createNewPlayer(String username) throws MudCloneException {
logger.info("creating new player");
MudObject obj = loadObject(getPlayerImpl().getHandle());
Player player = (Player) cloneObject(obj, false);
String upperName = username.substring(0, 1).toUpperCase() + username.substring(1);
player.setName(upperName);
player.addShortName(upperName);
player.addShortName(username);
return player;
}
public void savePlayerData(Player player) {
logger.info("saving player..");
try {
persistence.saveObject(PLAYER_STORE + player.getPlayerCredentials().getUsername(), player);
} catch (Exception e) {
try {
player.getTerminalOutput().writeln(e.getMessage());
} catch (IOException e1) {
logger.error(e1, e1);
}
logger.error(e, e);
}
}
public ObjectLocation getTheVoid() {
return theVoid;
}
public void setTheVoid(ObjectLocation voidLocation) {
this.theVoid = voidLocation;
}
public ObjectLocation getPlayerImpl() {
return playerImpl;
}
public void setPlayerImpl(ObjectLocation playerLoc) {
this.playerImpl = playerLoc;
}
public GroovyScriptEngine getGroovyScriptEngine() {
return groovyScriptEngine;
}
public void setGroovyScriptEngine(GroovyScriptEngine gse) {
this.groovyScriptEngine = gse;
}
public Registry getObjectRegistry() {
return objectRegistry;
}
public MudDataSource<MudObject> getPersistence() {
return persistence;
}
public void setPersistence(MudDataSource<MudObject> datasource) {
this.persistence = datasource;
}
/**
* @return the domainManagers
*/
public List<DomainManager<MudObject>> getDomainManagers() {
return domainManagers;
}
/**
* @param domainManagers the domainManagers to set
*/
public void setDomainManagers(List<DomainManager<MudObject>> domainManagers) {
this.domainManagers = domainManagers;
}
/**
* @return the xstream
*/
public XStream getXstream() {
return xstream;
}
/**
* @param xstream the xstream to set
*/
public void setXstream(XStream xstream) {
this.xstream = xstream;
}
}