diff --git a/l2jserver2-common/src/assembly/distribution-h2-bin.xml b/l2jserver2-common/src/assembly/distribution-h2-bin.xml new file mode 100644 index 000000000..59b6145fa --- /dev/null +++ b/l2jserver2-common/src/assembly/distribution-h2-bin.xml @@ -0,0 +1,54 @@ + + h2-bin + + + + zip + + + + + ${project.basedir} + / + + data/** + + + .gitignore + data/cache/** + data/pathing.db + data/database.h2.* + + + + ${project.basedir}/distribution/global + / + + + ${project.basedir}/distribution/sql + / + + + ${project.build.directory} + / + + ${project.artifactId}-${project.version}.jar + + + + + + /libs + false + false + runtime + + mysql:* + com.orientechnologies:* + + + + diff --git a/l2jserver2-common/src/assembly/distribution-mysql5-bin.xml b/l2jserver2-common/src/assembly/distribution-mysql5-bin.xml new file mode 100644 index 000000000..4356408ab --- /dev/null +++ b/l2jserver2-common/src/assembly/distribution-mysql5-bin.xml @@ -0,0 +1,54 @@ + + mysql5-bin + + + + zip + + + + + ${project.basedir} + / + + data/** + + + .gitignore + data/cache/** + data/pathing.db + data/database.h2.* + + + + ${project.basedir}/distribution/global + / + + + ${project.basedir}/distribution/sql + / + + + ${project.build.directory} + / + + ${project.artifactId}-${project.version}.jar + + + + + + /libs + false + false + runtime + + com.h2database:* + com.orientechnologies:* + + + + diff --git a/l2jserver2-common/src/assembly/distribution-orientdb-bin.xml b/l2jserver2-common/src/assembly/distribution-orientdb-bin.xml new file mode 100644 index 000000000..d95950133 --- /dev/null +++ b/l2jserver2-common/src/assembly/distribution-orientdb-bin.xml @@ -0,0 +1,51 @@ + + orientdb-bin + + + + zip + + + + + ${project.basedir} + / + + data/** + + + .gitignore + data/cache/** + data/pathing.db + data/database.h2.* + + + + ${project.basedir}/distribution/global + / + + + ${project.build.directory} + / + + ${project.artifactId}-${project.version}.jar + + + + + + /libs + false + false + runtime + + mysql:* + com.h2database:* + commons-dbcp:* + + + + \ No newline at end of file diff --git a/l2jserver2-common/src/assembly/distribution-src.xml b/l2jserver2-common/src/assembly/distribution-src.xml new file mode 100644 index 000000000..f28a36822 --- /dev/null +++ b/l2jserver2-common/src/assembly/distribution-src.xml @@ -0,0 +1,34 @@ + + src + + + + zip + + + + + ${project.basedir} + / + + data/** + src/** + + + + ${project.basedir}/dist + / + + + + + /libs + false + false + runtime + + + diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractJDBCDatabaseService.java b/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractJDBCDatabaseService.java index 64926d32e..d470ee46e 100644 --- a/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractJDBCDatabaseService.java +++ b/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractJDBCDatabaseService.java @@ -96,6 +96,10 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService * The thread service */ private final ThreadService threadService; + /** + * The {@link DAOResolver} instance + */ + private final DAOResolver daoResolver; /** * The database connection pool @@ -258,13 +262,17 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService * the cache service * @param threadService * the thread service + * @param daoResolver + * the {@link DataAccessObject DAO} resolver */ @Inject public AbstractJDBCDatabaseService(ConfigurationService configService, - CacheService cacheService, ThreadService threadService) { + CacheService cacheService, ThreadService threadService, + DAOResolver daoResolver) { config = configService.get(JDBCDatabaseConfiguration.class); this.cacheService = cacheService; this.threadService = threadService; + this.daoResolver = daoResolver; } @Override @@ -298,8 +306,8 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService int objects = 0; for (final Model object : objectCache) { @SuppressWarnings("unchecked") - final DataAccessObject, ?> dao = getDAO(object - .getClass()); + final DataAccessObject, ?> dao = (DataAccessObject, ?>) daoResolver + .getDAO(object.getClass()); if (dao.save(object)) { objects++; } diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractOrientDatabaseService.java b/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractOrientDatabaseService.java new file mode 100644 index 000000000..7b3c6f3e6 --- /dev/null +++ b/l2jserver2-common/src/main/java/com/l2jserver/service/database/AbstractOrientDatabaseService.java @@ -0,0 +1,690 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.service.database; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.inject.Inject; +import com.l2jserver.model.Model; +import com.l2jserver.model.Model.ObjectDesire; +import com.l2jserver.model.id.ID; +import com.l2jserver.model.id.object.allocator.IDAllocator; +import com.l2jserver.service.AbstractService; +import com.l2jserver.service.ServiceStartException; +import com.l2jserver.service.ServiceStopException; +import com.l2jserver.service.cache.Cache; +import com.l2jserver.service.cache.CacheService; +import com.l2jserver.service.configuration.ConfigurationService; +import com.l2jserver.service.configuration.ProxyConfigurationService.ConfigurationPropertiesKey; +import com.l2jserver.service.configuration.XMLConfigurationService.ConfigurationXPath; +import com.l2jserver.service.core.threading.ScheduledAsyncFuture; +import com.l2jserver.service.core.threading.ThreadService; +import com.l2jserver.util.ArrayIterator; +import com.l2jserver.util.factory.CollectionFactory; +import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; +import com.orientechnologies.orient.core.query.nativ.ONativeSynchQuery; +import com.orientechnologies.orient.core.query.nativ.OQueryContextNativeSchema; +import com.orientechnologies.orient.core.record.impl.ODocument; + +/** + * This is an implementation of {@link DatabaseService} that provides an layer + * to JDBC. + * + *

Internal specification

The {@link Query} object

+ * + * If you wish to implement a new {@link DataAccessObject} you should try not + * use {@link Query} object directly because it only provides low level access + * to the JDBC architecture. Instead, you could use an specialized class, like + * {@link InsertUpdateQuery}, {@link SelectListQuery} or + * {@link SelectSingleQuery}. If you do need low level access, feel free to use + * the {@link Query} class directly. + * + *

The {@link Mapper} object

+ * + * The {@link Mapper} object maps an JDBC {@link ResultSet} into an Java + * {@link Object}. All {@link Model} objects support {@link CachedMapper} that + * will cache result based on its {@link ID} and always use the same object with + * the same {@link ID}. + * + * @author Rogiel + */ +public abstract class AbstractOrientDatabaseService extends AbstractService + implements DatabaseService { + /** + * The configuration object + */ + private final OrientDatabaseConfiguration config; + /** + * The logger + */ + private final Logger log = LoggerFactory + .getLogger(AbstractOrientDatabaseService.class); + + /** + * The cache service + */ + private final CacheService cacheService; + /** + * The thread service + */ + private final ThreadService threadService; + /** + * The {@link DAOResolver} instance + */ + private final DAOResolver daoResolver; + + private ODatabaseDocumentTx database; + + /** + * An cache object + */ + private Cache> objectCache; + /** + * Future for the auto-save task. Each object that has changed is auto saved + * every 1 minute. + */ + private ScheduledAsyncFuture autoSaveFuture; + + /** + * Configuration interface for {@link AbstractOrientDatabaseService}. + * + * @author Rogiel + */ + public interface OrientDatabaseConfiguration extends DatabaseConfiguration { + /** + * @return the orientdb url + */ + @ConfigurationPropertyGetter(defaultValue = "file:data/database") + @ConfigurationPropertiesKey("orientdb.url") + @ConfigurationXPath("/configuration/services/database/orientdb/url") + String getUrl(); + + /** + * @param url + * the new orientdb url + */ + @ConfigurationPropertySetter + @ConfigurationPropertiesKey("orientdb.url") + @ConfigurationXPath("/configuration/services/database/orientdb/url") + void setUrl(String url); + + /** + * @return the orientdb database username + */ + @ConfigurationPropertyGetter(defaultValue = "l2j") + @ConfigurationPropertiesKey("orientdb.username") + @ConfigurationXPath("/configuration/services/database/orientdb/username") + String getUsername(); + + /** + * @param username + * the orientdb database username + */ + @ConfigurationPropertySetter + @ConfigurationPropertiesKey("orientdb.username") + @ConfigurationXPath("/configuration/services/database/orientdb/username") + void setUsername(String username); + + /** + * @return the orientdb database password + */ + @ConfigurationPropertyGetter(defaultValue = "changeme") + @ConfigurationPropertiesKey("orientdb.password") + @ConfigurationXPath("/configuration/services/database/orientdb/password") + String getPassword(); + + /** + * @param password + * the jdbc database password + */ + @ConfigurationPropertySetter + @ConfigurationPropertiesKey("jdbc.password") + @ConfigurationXPath("/configuration/services/database/jdbc/password") + void setPassword(String password); + } + + /** + * @param configService + * the configuration service + * @param cacheService + * the cache service + * @param threadService + * the thread service + * @param daoResolver + * the {@link DataAccessObject DAO} resolver + */ + @Inject + public AbstractOrientDatabaseService(ConfigurationService configService, + CacheService cacheService, ThreadService threadService, + DAOResolver daoResolver) { + config = configService.get(OrientDatabaseConfiguration.class); + this.cacheService = cacheService; + this.threadService = threadService; + this.daoResolver = daoResolver; + } + + @Override + protected void doStart() throws ServiceStartException { + database = new ODatabaseDocumentTx(config.getUrl()); + if (!database.exists()) { + database.create(); + } else { + database.open(config.getUsername(), config.getPassword()); + } + + // cache must be large enough for all world objects, to avoid + // duplication... this would endanger non-persistent states + objectCache = cacheService.createEternalCache("database-service", + IDAllocator.ALLOCABLE_IDS); + + // start the auto save task + autoSaveFuture = threadService.async(60, TimeUnit.SECONDS, 60, + new Runnable() { + @Override + public void run() { + log.debug("Auto save task started"); + int objects = 0; + for (final Model object : objectCache) { + @SuppressWarnings("unchecked") + final DataAccessObject, ?> dao = daoResolver + .getDAO(object.getClass()); + if (dao.save(object)) { + objects++; + } + } + log.info( + "{} objects have been saved by the auto save task", + objects); + } + }); + } + + /** + * Executes an query in the database. + * + * @param + * the query return type + * @param query + * the query + * @return an instance of T + */ + public T query(Query query) { + Preconditions.checkNotNull(query, "query"); + log.debug("Executing query {} with {}", query, database); + try { + return query.query(database); + } catch (SQLException e) { + log.error("Database error", e); + return null; + } + } + + /** + * Checks for the cached version of the object + * + * @param id + * the object ID + * @return the cached version, if any + */ + public Object getCachedObject(Object id) { + Preconditions.checkNotNull(id, "id"); + log.debug("Fetching cached object {}", id); + return objectCache.get(id); + } + + /** + * Checks for the cached version of the object + * + * @param id + * the object ID + * @return true if has an cached version, + */ + public boolean hasCachedObject(Object id) { + Preconditions.checkNotNull(id, "id"); + log.debug("Locating cached object {}", id); + return objectCache.contains(id); + } + + /** + * Updates an cache object + * + * @param id + * the cache key + * @param value + * the model value + */ + public void updateCache(ID id, Model value) { + Preconditions.checkNotNull(id, "key"); + Preconditions.checkNotNull(value, "value"); + log.debug("Updating cached object {} with {}", id, value); + objectCache.put(id, value); + } + + /** + * Removes an cached object + * + * @param id + * the object id + */ + public void removeCache(Object id) { + Preconditions.checkNotNull(id, "key"); + log.debug("Removing cached object {}", id); + objectCache.remove(id); + } + + @Override + protected void doStop() throws ServiceStopException { + autoSaveFuture.cancel(true); + autoSaveFuture = null; + cacheService.dispose(objectCache); + objectCache = null; + database.close(); + database = null; + } + + /** + * The query interface. The query will receive an connection an will be + * executed. The can return return a value if required. + * + * @author Rogiel + * + * @param + * the return type + */ + public interface Query { + /** + * Execute the query in conn + * + * @param database + * the database connection + * @return the query return value + * @throws SQLException + * if any SQL error occur + */ + R query(ODatabaseDocumentTx database) throws SQLException; + } + + /** + * This query is used for the following statements: + *
    + *
  • INSERT INTO
  • + *
  • UPDATE
  • + *
  • DELETE FROM
  • + *
+ * + * @author Rogiel + * + * @param + * the query return type + */ + public static abstract class InsertUpdateQuery implements Query { + /** + * The logger + */ + private final Logger log = LoggerFactory + .getLogger(InsertUpdateQuery.class); + + /** + * The iterator + */ + private final Iterator iterator; + + /** + * Creates a new query for objects + * + * @param objects + * the object list + */ + public InsertUpdateQuery(T... objects) { + this(new ArrayIterator(objects)); + } + + /** + * Create a new query for objects in iterator + * + * @param iterator + * the object iterator + */ + public InsertUpdateQuery(Iterator iterator) { + this.iterator = iterator; + } + + @Override + public Integer query(ODatabaseDocumentTx database) throws SQLException { + Preconditions.checkNotNull(database, "database"); + + log.debug("Starting INSERT/UPDATE query execution"); + + int rows = 0; + while (iterator.hasNext()) { + final T object = iterator.next(); + final ONativeSynchQuery> query = createQuery( + database, object); + final ODocument document; + if (query != null) { + List docs = database.query(query); + if (docs.size() >= 1) { + document = update(docs.get(0), object); + } else { + continue; + } + } else { + document = insert(new ODocument(), object); + } + if (document != null) + database.save(document); + rows++; + } + return rows; + } + + /** + * Creates the prepared query for execution + * + * @param database + * the database + * @param object + * the object that is being updated + * + * @return the prepared query. If null is returned a + * insert query will be performed. + */ + protected abstract ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database, T object); + + /** + * Set the parameters in document for object. The + * object can be removed calling {@link ODocument#delete()} and + * returning null + * + * @param document + * the document + * @param object + * the object + * @return the updated document. Can be null + * @throws SQLException + * if any SQL error occur + */ + protected abstract ODocument update(ODocument document, T object) + throws SQLException; + + /** + * Set the parameters for in statement for object + * + * @param document + * the document + * @param object + * the object + * @return the filled document + * @throws SQLException + * if any SQL error occur + */ + protected abstract ODocument insert(ODocument document, T object) + throws SQLException; + + /** + * Return the key mapper. Can be null if no generated keys are used or + * are not important. + * + * @return the key mapper + */ + protected Mapper> keyMapper() { + return null; + } + } + + /** + * An select query that returns a list of objects of type T + * + * @author Rogiel + * + * @param + * the query return type + */ + public static abstract class SelectListQuery implements Query> { + /** + * The logger + */ + private final Logger log = LoggerFactory + .getLogger(SelectListQuery.class); + + @Override + public List query(ODatabaseDocumentTx database) throws SQLException { + Preconditions.checkNotNull(database, "database"); + + log.debug("Starting SELECT List query execution"); + + List result = database.query(createQuery(database)); + final List list = CollectionFactory.newList(); + final Mapper mapper = mapper(); + log.debug("Database returned {}", result); + for (final ODocument document : result) { + log.debug("Mapping row with {}", mapper); + final T obj = mapper.map(document); + if (obj == null) { + log.debug("Mapper {} returned a null row", mapper); + continue; + } + if (obj instanceof Model) + ((Model) obj).setObjectDesire(ObjectDesire.NONE); + log.debug("Mapper {} returned {}", mapper, obj); + list.add(obj); + } + return list; + } + + /** + * Creates the prepared query for execution + * + * @param database + * the database + * + * @return the prepared query + */ + protected abstract ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database); + + /** + * Return the mapper that will bind {@link ResultSet} objects into an + * T object instance. The mapper will need to create the object + * instance. + *

+ * Note: This method will be called for each row, an thus is a + * good idea to create a new instance on each call! + * + * @return the mapper instance + */ + protected abstract Mapper mapper(); + } + + /** + * An select query that returns a single object of type T + * + * @author Rogiel + * + * @param + * the query return type + */ + public static abstract class SelectSingleQuery implements Query { + /** + * The logger + */ + private final Logger log = LoggerFactory + .getLogger(SelectSingleQuery.class); + + @Override + public T query(ODatabaseDocumentTx database) throws SQLException { + Preconditions.checkNotNull(database, "database"); + + log.debug("Starting SELECT single query execution"); + + List result = database.query(createQuery(database)); + final Mapper mapper = mapper(); + log.debug("Database returned {}", result); + for (final ODocument document : result) { + log.debug("Mapping row with {}", mapper); + final T obj = mapper.map(document); + if (obj == null) { + log.debug("Mapper {} returned a null row", mapper); + continue; + } + if (obj instanceof Model) + ((Model) obj).setObjectDesire(ObjectDesire.NONE); + log.debug("Mapper {} returned {}", mapper, obj); + return obj; + } + return null; + } + + /** + * Creates the prepared query for execution + * + * @param database + * the database + * + * @return the prepared query + */ + protected abstract ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database); + + /** + * Return the mapper that will bind {@link ResultSet} objects into an + * T object instance. The mapper will need to create the object + * instance. + *

+ * Note: This method will be called for each row, an thus is a + * good idea to create a new instance on each call! + * + * @return the mapper instance + */ + protected abstract Mapper mapper(); + } + + /** + * The {@link Mapper} maps an {@link ResultSet} into an object T + * + * @author Rogiel + * + * @param + * the object type + */ + public interface Mapper { + /** + * Map the result set value into an object. + *

+ * Note: it is required to call {@link ResultSet#next()}, since + * it is called by the {@link Query}. + * + * @param document + * the resulted document + * @return the created instance + * @throws SQLException + * if any SQL error occur + */ + T map(ODocument document) throws SQLException; + } + + /** + * The cached mapper will try to lookup the result in the cache, before + * create a new instance. If the instance is not found in the cache, then + * the {@link Mapper} implementation is called to create the object. Note + * that the ID, used for the cache lookup, will be reused. After creation, + * the cache is updated. + * + * @author Rogiel + * + * @param + * the object type + * @param + * the id type + */ + public abstract static class CachedMapper, I extends ID> + implements Mapper { + /** + * The logger + */ + private final Logger log = LoggerFactory + .getLogger(SelectSingleQuery.class); + + /** + * The database service instance + */ + private final AbstractOrientDatabaseService database; + + /** + * The {@link ID} mapper + */ + private final Mapper idMapper; + + /** + * Creates a new instance + * + * @param database + * the database service + * @param idMapper + * the {@link ID} {@link Mapper} + */ + public CachedMapper(AbstractOrientDatabaseService database, + Mapper idMapper) { + this.database = database; + this.idMapper = idMapper; + } + + @Override + @SuppressWarnings("unchecked") + public final T map(ODocument document) throws SQLException { + log.debug("Mapping row {} ID with {}", document, idMapper); + final I id = idMapper.map(document); + Preconditions.checkNotNull(id, "id"); + + log.debug("ID={}, locating cached object", id); + + if (database.hasCachedObject(id)) + return (T) database.getCachedObject(id); + + log.debug("Cached object not found, creating..."); + + final T object = map(id, document); + if (object != null) + database.updateCache(id, object); + log.debug("Object {} created", object); + return object; + } + + /** + * Maps an uncached object. Once mapping is complete, it will be added + * to the cache. + * + * @param id + * the object id + * @param document + * the document result + * @return the created object + * @throws SQLException + * if any SQL error occur + */ + protected abstract T map(I id, ODocument document) throws SQLException; + } +} diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/database/DAOResolver.java b/l2jserver2-common/src/main/java/com/l2jserver/service/database/DAOResolver.java new file mode 100644 index 000000000..edf8e2007 --- /dev/null +++ b/l2jserver2-common/src/main/java/com/l2jserver/service/database/DAOResolver.java @@ -0,0 +1,66 @@ +package com.l2jserver.service.database; + +import com.l2jserver.model.Model; +import com.l2jserver.model.id.ID; + +public interface DAOResolver { + /** + * Returns the {@link DataAccessObject} used to retrieve and save objects of + * type + * + * @param + * the {@link Model} type + * @param + * the {@link ID} type + * @param modelObject + * the model object + * @return the {@link DataAccessObject} for {@link Model} + */ + , M extends Model> DataAccessObject getDAO( + M modelObject); + + /** + * Returns the {@link DataAccessObject} used to retrieve and save objects of + * type + * + * @param + * the {@link Model} type + * @param + * the {@link ID} type + * @param modelClass + * the model class + * @return the {@link DataAccessObject} for {@link Model} + */ + , I extends ID> DataAccessObject getDAO( + Class modelClass); + + /** + * Returns the {@link DataAccessObject} used to retrieve and save objects of + * type M which use {@link ID} of type I + * + * @param + * the {@link Model} type + * @param + * the {@link ID} type + * @param modelIdObject + * the model {@link ID} object + * @return the {@link DataAccessObject} for {@link Model} + */ + , M extends Model> DataAccessObject getDAOFromID( + I modelIdObject); + + /** + * Returns the {@link DataAccessObject} used to retrieve and save objects of + * type M which use {@link ID} of type I + * + * @param + * the {@link Model} type + * @param + * the {@link ID} type + * @param modelIdType + * the model {@link ID} class + * @return the {@link DataAccessObject} for {@link Model} + */ + , M extends Model> DataAccessObject getDAOFromID( + Class modelIdType); +} diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/database/DatabaseService.java b/l2jserver2-common/src/main/java/com/l2jserver/service/database/DatabaseService.java index d04698857..492052884 100644 --- a/l2jserver2-common/src/main/java/com/l2jserver/service/database/DatabaseService.java +++ b/l2jserver2-common/src/main/java/com/l2jserver/service/database/DatabaseService.java @@ -16,8 +16,6 @@ */ package com.l2jserver.service.database; -import com.l2jserver.model.Model; -import com.l2jserver.model.id.ID; import com.l2jserver.service.Service; import com.l2jserver.service.ServiceConfiguration; import com.l2jserver.service.configuration.Configuration; @@ -48,19 +46,4 @@ public interface DatabaseService extends Service { @ConfigurationName("database") public interface DatabaseConfiguration extends ServiceConfiguration { } - - /** - * Returns the {@link DataAccessObject} used to retrieve and save objects of - * type - * - * @param - * the {@link Model} type - * @param - * the {@link ID} type - * @param model - * the model class - * @return the {@link DataAccessObject} for {@link Model} - */ - , I extends ID> DataAccessObject getDAO( - Class model); } diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/database/orientdb/AbstractOrientDBDAO.java b/l2jserver2-common/src/main/java/com/l2jserver/service/database/orientdb/AbstractOrientDBDAO.java new file mode 100644 index 000000000..c0d398d9e --- /dev/null +++ b/l2jserver2-common/src/main/java/com/l2jserver/service/database/orientdb/AbstractOrientDBDAO.java @@ -0,0 +1,44 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.service.database.orientdb; + +import com.l2jserver.model.Model; +import com.l2jserver.model.id.ID; +import com.l2jserver.service.database.AbstractDAO; +import com.l2jserver.service.database.AbstractOrientDatabaseService; +import com.l2jserver.service.database.DatabaseService; + +/** + * @author Rogiel + * @param + * the model type + * @param + * the id type + */ +public abstract class AbstractOrientDBDAO, I extends ID> + extends AbstractDAO { + protected final AbstractOrientDatabaseService database; + + /** + * @param database + * the database instance + */ + protected AbstractOrientDBDAO(DatabaseService database) { + super(database); + this.database = (AbstractOrientDatabaseService) database; + } +} diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerDAOResolver.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerDAOResolver.java new file mode 100644 index 000000000..38e447175 --- /dev/null +++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerDAOResolver.java @@ -0,0 +1,101 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.service.database; + +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.l2jserver.model.Model; +import com.l2jserver.model.dao.CharacterDAO; +import com.l2jserver.model.dao.ClanDAO; +import com.l2jserver.model.dao.ItemDAO; +import com.l2jserver.model.dao.NPCDAO; +import com.l2jserver.model.dao.PetDAO; +import com.l2jserver.model.id.ID; +import com.l2jserver.model.id.object.CharacterID; +import com.l2jserver.model.id.object.ClanID; +import com.l2jserver.model.id.object.ItemID; +import com.l2jserver.model.id.object.NPCID; +import com.l2jserver.model.id.object.PetID; +import com.l2jserver.model.world.Clan; +import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.model.world.NPC; +import com.l2jserver.model.world.Pet; +import com.l2jserver.util.ClassUtils; + +/** + * @author Rogiel + * + */ +public class GameServerDAOResolver implements DAOResolver { + private final Injector injector; + + @Inject + private GameServerDAOResolver(Injector injector) { + this.injector = injector; + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public , M extends Model> DataAccessObject getDAO( + M modelObject) { + return (DataAccessObject) getDAO(modelObject.getClass()); + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public , I extends ID> DataAccessObject getDAO( + Class modelClass) { + if (ClassUtils.isSubclass(modelClass, L2Character.class)) { + return (DataAccessObject) injector.getInstance(CharacterDAO.class); + } else if (ClassUtils.isSubclass(modelClass, Clan.class)) { + return (DataAccessObject) injector.getInstance(ClanDAO.class); + } else if (ClassUtils.isSubclass(modelClass, Item.class)) { + return (DataAccessObject) injector.getInstance(ItemDAO.class); + } else if (ClassUtils.isSubclass(modelClass, NPC.class)) { + return (DataAccessObject) injector.getInstance(NPCDAO.class); + } else if (ClassUtils.isSubclass(modelClass, Pet.class)) { + return (DataAccessObject) injector.getInstance(PetDAO.class); + } + return null; + } + + @Override + @SuppressWarnings({ "unchecked" }) + public , M extends Model> DataAccessObject getDAOFromID( + I modelIdObject) { + return (DataAccessObject) getDAOFromID(modelIdObject.getClass()); + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public , M extends Model> DataAccessObject getDAOFromID( + Class modelIdType) { + if (ClassUtils.isSubclass(modelIdType, CharacterID.class)) { + return (DataAccessObject) injector.getInstance(CharacterDAO.class); + } else if (ClassUtils.isSubclass(modelIdType, ClanID.class)) { + return (DataAccessObject) injector.getInstance(ClanDAO.class); + } else if (ClassUtils.isSubclass(modelIdType, ItemID.class)) { + return (DataAccessObject) injector.getInstance(ItemDAO.class); + } else if (ClassUtils.isSubclass(modelIdType, NPCID.class)) { + return (DataAccessObject) injector.getInstance(NPCDAO.class); + } else if (ClassUtils.isSubclass(modelIdType, PetID.class)) { + return (DataAccessObject) injector.getInstance(PetDAO.class); + } + return null; + } +} diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerJDBCDatabaseService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerJDBCDatabaseService.java index d2b0040db..e1c23916d 100644 --- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerJDBCDatabaseService.java +++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerJDBCDatabaseService.java @@ -18,26 +18,15 @@ package com.l2jserver.service.database; import java.sql.ResultSet; -import com.google.inject.Injector; +import com.google.inject.Inject; import com.l2jserver.model.Model; -import com.l2jserver.model.dao.CharacterDAO; -import com.l2jserver.model.dao.ClanDAO; -import com.l2jserver.model.dao.ItemDAO; -import com.l2jserver.model.dao.NPCDAO; -import com.l2jserver.model.dao.PetDAO; import com.l2jserver.model.id.ID; -import com.l2jserver.model.world.Clan; -import com.l2jserver.model.world.Item; -import com.l2jserver.model.world.L2Character; -import com.l2jserver.model.world.NPC; -import com.l2jserver.model.world.Pet; import com.l2jserver.service.AbstractService.Depends; import com.l2jserver.service.cache.CacheService; import com.l2jserver.service.configuration.ConfigurationService; import com.l2jserver.service.core.LoggingService; import com.l2jserver.service.core.threading.ThreadService; import com.l2jserver.service.game.template.TemplateService; -import com.l2jserver.util.ClassUtils; /** * This is an implementation of {@link DatabaseService} that provides an layer @@ -77,43 +66,20 @@ import com.l2jserver.util.ClassUtils; ConfigurationService.class, TemplateService.class, ThreadService.class }) public class GameServerJDBCDatabaseService extends AbstractJDBCDatabaseService implements DatabaseService { - /** - * The Google Guice {@link Injector}. It is used to get DAO instances. - */ - private final Injector injector; - /** * @param configService * the config service - * @param injector - * the Guice {@link Injector} * @param cacheService * the cache service * @param threadService * the thread service + * @param daoResolver + * the {@link DataAccessObject DAO} resolver */ + @Inject public GameServerJDBCDatabaseService(ConfigurationService configService, - Injector injector, CacheService cacheService, - ThreadService threadService) { - super(configService, cacheService, threadService); - this.injector = injector; - } - - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - public , I extends ID> DataAccessObject getDAO( - Class model) { - if (ClassUtils.isSubclass(model, L2Character.class)) { - return (DataAccessObject) injector.getInstance(CharacterDAO.class); - } else if (ClassUtils.isSubclass(model, Clan.class)) { - return (DataAccessObject) injector.getInstance(ClanDAO.class); - } else if (ClassUtils.isSubclass(model, Item.class)) { - return (DataAccessObject) injector.getInstance(ItemDAO.class); - } else if (ClassUtils.isSubclass(model, NPC.class)) { - return (DataAccessObject) injector.getInstance(NPCDAO.class); - } else if (ClassUtils.isSubclass(model, Pet.class)) { - return (DataAccessObject) injector.getInstance(PetDAO.class); - } - return null; + CacheService cacheService, ThreadService threadService, + DAOResolver daoResolver) { + super(configService, cacheService, threadService, daoResolver); } } diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerOrientDatabaseService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerOrientDatabaseService.java new file mode 100644 index 000000000..c52e5a198 --- /dev/null +++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/GameServerOrientDatabaseService.java @@ -0,0 +1,85 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.service.database; + +import java.sql.ResultSet; + +import com.google.inject.Inject; +import com.l2jserver.model.Model; +import com.l2jserver.model.id.ID; +import com.l2jserver.service.AbstractService.Depends; +import com.l2jserver.service.cache.CacheService; +import com.l2jserver.service.configuration.ConfigurationService; +import com.l2jserver.service.core.LoggingService; +import com.l2jserver.service.core.threading.ThreadService; +import com.l2jserver.service.game.template.TemplateService; + +/** + * This is an implementation of {@link DatabaseService} that provides an layer + * to JDBC. + * + *

Internal specification

The + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.Query + * Query} object

+ * + * If you wish to implement a new {@link DataAccessObject} you should try not + * use {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.Query + * Query} object directly because it only provides low level access to the JDBC + * architecture. Instead, you could use an specialized class, like + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.InsertUpdateQuery + * InsertUpdateQuery} , + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.SelectListQuery + * SelectListQuery} or + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.SelectSingleQuery + * SelectSingleQuery} . If you do need low level access, feel free to use the + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.Query + * Query} class directly. + * + *

The + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.Mapper + * Mapper} object

+ * + * The {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.Mapper + * Mapper} object maps an JDBC {@link ResultSet} into an Java {@link Object}. + * All {@link Model} objects support + * {@link com.l2jserver.service.database.AbstractJDBCDatabaseService.CachedMapper + * CachedMapper} that will cache result based on its {@link ID} and always use + * the same object with the same {@link ID}. + * + * @author Rogiel + */ +@Depends({ LoggingService.class, CacheService.class, + ConfigurationService.class, TemplateService.class, ThreadService.class }) +public class GameServerOrientDatabaseService extends + AbstractOrientDatabaseService implements DatabaseService { + /** + * @param configService + * the config service + * @param cacheService + * the cache service + * @param threadService + * the thread service + * @param daoResolver + * the {@link DataAccessObject DAO} resolver + */ + @Inject + public GameServerOrientDatabaseService(ConfigurationService configService, + CacheService cacheService, ThreadService threadService, + DAOResolver daoResolver) { + super(configService, cacheService, threadService, daoResolver); + } +} diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/orientdb/AbstractOrientDBDAO.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/orientdb/AbstractOrientDBDAO.java new file mode 100644 index 000000000..c0d398d9e --- /dev/null +++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/orientdb/AbstractOrientDBDAO.java @@ -0,0 +1,44 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.service.database.orientdb; + +import com.l2jserver.model.Model; +import com.l2jserver.model.id.ID; +import com.l2jserver.service.database.AbstractDAO; +import com.l2jserver.service.database.AbstractOrientDatabaseService; +import com.l2jserver.service.database.DatabaseService; + +/** + * @author Rogiel + * @param + * the model type + * @param + * the id type + */ +public abstract class AbstractOrientDBDAO, I extends ID> + extends AbstractDAO { + protected final AbstractOrientDatabaseService database; + + /** + * @param database + * the database instance + */ + protected AbstractOrientDBDAO(DatabaseService database) { + super(database); + this.database = (AbstractOrientDatabaseService) database; + } +} diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/orientdb/OrientDBCharacterDAO.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/orientdb/OrientDBCharacterDAO.java new file mode 100644 index 000000000..701514500 --- /dev/null +++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/database/orientdb/OrientDBCharacterDAO.java @@ -0,0 +1,465 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.service.database.orientdb; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; + +import com.google.inject.Inject; +import com.l2jserver.model.dao.CharacterDAO; +import com.l2jserver.model.id.AccountID; +import com.l2jserver.model.id.object.CharacterID; +import com.l2jserver.model.id.object.ClanID; +import com.l2jserver.model.id.object.provider.CharacterIDProvider; +import com.l2jserver.model.id.object.provider.ClanIDProvider; +import com.l2jserver.model.id.provider.AccountIDProvider; +import com.l2jserver.model.id.template.CharacterTemplateID; +import com.l2jserver.model.id.template.provider.CharacterTemplateIDProvider; +import com.l2jserver.model.template.CharacterTemplate; +import com.l2jserver.model.template.actor.ActorSex; +import com.l2jserver.model.template.character.CharacterClass; +import com.l2jserver.model.template.character.CharacterRace; +import com.l2jserver.model.world.Clan; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.model.world.character.CharacterAppearance; +import com.l2jserver.model.world.character.CharacterAppearance.CharacterFace; +import com.l2jserver.model.world.character.CharacterAppearance.CharacterHairColor; +import com.l2jserver.model.world.character.CharacterAppearance.CharacterHairStyle; +import com.l2jserver.service.database.AbstractOrientDatabaseService.CachedMapper; +import com.l2jserver.service.database.AbstractOrientDatabaseService.InsertUpdateQuery; +import com.l2jserver.service.database.AbstractOrientDatabaseService.Mapper; +import com.l2jserver.service.database.AbstractOrientDatabaseService.SelectListQuery; +import com.l2jserver.service.database.AbstractOrientDatabaseService.SelectSingleQuery; +import com.l2jserver.service.database.DatabaseService; +import com.l2jserver.util.geometry.Point3D; +import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; +import com.orientechnologies.orient.core.query.nativ.ONativeSynchQuery; +import com.orientechnologies.orient.core.query.nativ.OQueryContextNativeSchema; +import com.orientechnologies.orient.core.record.impl.ODocument; + +/** + * @author Rogiel + * + */ +public class OrientDBCharacterDAO extends + AbstractOrientDBDAO implements CharacterDAO { + /** + * The {@link CharacterID} factory + */ + private final CharacterIDProvider idFactory; + /** + * The {@link CharacterTemplateID} factory + */ + private final CharacterTemplateIDProvider templateIdFactory; + /** + * The {@link AccountID} factory + */ + private final AccountIDProvider accountIdFactory; + /** + * The {@link ClanID} factory + */ + private final ClanIDProvider clanIdFactory; + + /** + * Character table name + */ + public static final String CLASS_NAME = L2Character.class.getSimpleName(); + // FIELDS + public static final String CHAR_ID = "character_id"; + public static final String ACCOUNT_ID = "account_id"; + public static final String CLAN_ID = "clan_id"; + public static final String NAME = "name"; + + public static final String RACE = "race"; + public static final String CLASS = "class"; + public static final String SEX = "sex"; + + public static final String LEVEL = "level"; + public static final String EXPERIENCE = "experience"; + public static final String SP = "sp"; + + public static final String HP = "hp"; + public static final String MP = "mp"; + public static final String CP = "cp"; + + public static final String POINT_X = "point_x"; + public static final String POINT_Y = "point_y"; + public static final String POINT_Z = "point_z"; + public static final String POINT_ANGLE = "point_angle"; + + public static final String APPEARANCE_HAIR_STYLE = "appearance_hair_style"; + public static final String APPEARANCE_HAIR_COLOR = "appearance_hair_color"; + public static final String APPEARANCE_FACE = "apperance_face"; + + /** + * The mapper for {@link CharacterID} + */ + private final Mapper idMapper = new Mapper() { + @Override + public CharacterID map(ODocument document) throws SQLException { + return idFactory.resolveID((Integer) document.field(CHAR_ID)); + } + }; + + /** + * The {@link Mapper} for {@link L2Character} + */ + private final Mapper mapper = new CachedMapper( + database, idMapper) { + @Override + protected L2Character map(CharacterID id, ODocument document) + throws SQLException { + final CharacterClass charClass = (CharacterClass) document + .field(CLASS); + final CharacterTemplateID templateId = templateIdFactory + .resolveID(charClass.id); + final CharacterTemplate template = templateId.getTemplate(); + + final L2Character character = template.create(); + + character.setID(id); + character.setAccountID(accountIdFactory.resolveID((String) document + .field(ACCOUNT_ID))); + if (document.containsField(CLAN_ID)) + character.setClanID(clanIdFactory.resolveID((Integer) document + .field(CLAN_ID))); + + character.setName((String) document.field(NAME)); + + character.setRace((CharacterRace) document.field(RACE)); + character.setCharacterClass((CharacterClass) document.field(CLASS)); + character.setSex((ActorSex) document.field(SEX)); + + character.setLevel((Integer) document.field(LEVEL)); + character.setExperience((Long) document.field(EXPERIENCE)); + character.setSP((Integer) document.field(SP)); + + character.setHP((Double) document.field(HP)); + character.setMP((Double) document.field(MP)); + character.setCP((Double) document.field(CP)); + + character.setPoint(Point3D.fromXYZA( + (Integer) document.field(POINT_X), + (Integer) document.field(POINT_Y), + (Integer) document.field(POINT_Z), + (Double) document.field(POINT_ANGLE))); + + // appearance + character.getAppearance().setHairStyle( + (CharacterHairStyle) document.field(APPEARANCE_HAIR_STYLE)); + character.getAppearance().setHairColor( + (CharacterHairColor) document.field(APPEARANCE_HAIR_COLOR)); + character.getAppearance().setFace( + (CharacterFace) document.field(APPEARANCE_FACE)); + + return character; + } + }; + + /** + * @param database + * the database service + * @param idFactory + * the character id provider + * @param templateIdFactory + * the template id provider + * @param accountIdFactory + * the account id provider + * @param clanIdFactory + * the clan id provider + */ + @Inject + protected OrientDBCharacterDAO(DatabaseService database, + final CharacterIDProvider idFactory, + CharacterTemplateIDProvider templateIdFactory, + AccountIDProvider accountIdFactory, ClanIDProvider clanIdFactory) { + super(database); + this.idFactory = idFactory; + this.templateIdFactory = templateIdFactory; + this.accountIdFactory = accountIdFactory; + this.clanIdFactory = clanIdFactory; + } + + @Override + public L2Character select(final CharacterID id) { + return database.query(new SelectSingleQuery() { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database) { + return new ONativeSynchQuery>( + database, CLASS_NAME, + new OQueryContextNativeSchema()) { + private static final long serialVersionUID = 1L; + + @Override + public boolean filter( + OQueryContextNativeSchema criteria) { + return criteria.field(CHAR_ID).eq(id.getID()).go(); + }; + }; + } + + @Override + protected Mapper mapper() { + return mapper; + } + }); + } + + @Override + public Collection selectIDs() { + return database.query(new SelectListQuery() { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database) { + return new ONativeSynchQuery>( + database, CLASS_NAME, + new OQueryContextNativeSchema()) { + private static final long serialVersionUID = 1L; + + @Override + public boolean filter( + OQueryContextNativeSchema criteria) { + return true; + }; + }; + } + + @Override + protected Mapper mapper() { + return idMapper; + } + }); + } + + @Override + public boolean insert(L2Character object) { + return database.query(new InsertUpdateQuery(object) { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database, L2Character object) { + return null; + } + + @Override + protected ODocument update(ODocument document, L2Character character) + throws SQLException { + return null; + } + + @Override + protected ODocument insert(ODocument document, L2Character character) + throws SQLException { + final CharacterAppearance appearance = character + .getAppearance(); + + document.field(CHAR_ID, character.getID().getID()); + document.field(ACCOUNT_ID, character.getAccountID().getID()); + if (character.getClanID() != null) + document.field(CLAN_ID, character.getClanID().getID()); + + document.field(NAME, character.getName()); + + document.field(RACE, character.getRace().name()); + document.field(CLASS, character.getCharacterClass().name()); + document.field(SEX, character.getSex().name()); + + document.field(LEVEL, character.getLevel()); + document.field(EXPERIENCE, character.getExperience()); + document.field(SP, character.getSP()); + + document.field(HP, character.getHP()); + document.field(MP, character.getMP()); + document.field(CP, character.getCP()); + + document.field(POINT_X, character.getPoint().getX()); + document.field(POINT_Y, character.getPoint().getY()); + document.field(POINT_Z, character.getPoint().getZ()); + document.field(POINT_ANGLE, character.getPoint().getAngle()); + + // appearance + document.field(APPEARANCE_HAIR_STYLE, appearance.getHairStyle() + .name()); + document.field(APPEARANCE_HAIR_COLOR, appearance.getHairColor() + .name()); + document.field(APPEARANCE_FACE, appearance.getFace().name()); + + return document; + } + }) != 0; + } + + @Override + public boolean update(final L2Character character) { + return database.query(new InsertUpdateQuery(character) { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database, final L2Character character) { + return new ONativeSynchQuery>( + database, CLASS_NAME, + new OQueryContextNativeSchema()) { + private static final long serialVersionUID = 1L; + + @Override + public boolean filter( + OQueryContextNativeSchema criteria) { + return criteria.field(CHAR_ID) + .eq(character.getID().getID()).go(); + }; + }; + } + + @Override + protected ODocument update(ODocument document, L2Character character) + throws SQLException { + final CharacterAppearance appearance = character + .getAppearance(); + + document.field(ACCOUNT_ID, character.getAccountID().getID()); + if (character.getClanID() != null) + document.field(CLAN_ID, character.getClanID().getID()); + + document.field(NAME, character.getName()); + + document.field(RACE, character.getRace().name()); + document.field(CLASS, character.getCharacterClass().name()); + document.field(SEX, character.getSex().name()); + + document.field(LEVEL, character.getLevel()); + document.field(EXPERIENCE, character.getExperience()); + document.field(SP, character.getSP()); + + document.field(HP, character.getHP()); + document.field(MP, character.getMP()); + document.field(CP, character.getCP()); + + document.field(POINT_X, character.getPoint().getX()); + document.field(POINT_Y, character.getPoint().getY()); + document.field(POINT_Z, character.getPoint().getZ()); + document.field(POINT_ANGLE, character.getPoint().getAngle()); + + // appearance + document.field(APPEARANCE_HAIR_STYLE, appearance.getHairStyle() + .name()); + document.field(APPEARANCE_HAIR_COLOR, appearance.getHairColor() + .name()); + document.field(APPEARANCE_FACE, appearance.getFace().name()); + + return document; + } + + @Override + protected ODocument insert(ODocument document, L2Character character) + throws SQLException { + return null; + } + }) != 0; + } + + @Override + public boolean delete(L2Character object) { + return database.query(new InsertUpdateQuery(object) { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database, final L2Character character) { + return new ONativeSynchQuery>( + database, CLASS_NAME, + new OQueryContextNativeSchema()) { + private static final long serialVersionUID = 1L; + + @Override + public boolean filter( + OQueryContextNativeSchema criteria) { + return criteria.field(CHAR_ID) + .eq(character.getID().getID()).go(); + }; + }; + } + + @Override + protected ODocument update(ODocument document, L2Character character) + throws SQLException { + document.delete(); + return null; + } + + @Override + protected ODocument insert(ODocument document, L2Character character) + throws SQLException { + return null; + } + }) != 0; + } + + @Override + public void load(Clan clan) { + + } + + @Override + public L2Character selectByName(final String name) { + return database.query(new SelectSingleQuery() { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database) { + return new ONativeSynchQuery>( + database, CLASS_NAME, + new OQueryContextNativeSchema()) { + private static final long serialVersionUID = 1L; + + @Override + public boolean filter( + OQueryContextNativeSchema criteria) { + return criteria.field(NAME).eq(name).go(); + }; + }; + } + + @Override + protected Mapper mapper() { + return mapper; + } + }); + } + + @Override + public List selectByAccount(final AccountID account) { + return database.query(new SelectListQuery() { + @Override + protected ONativeSynchQuery> createQuery( + ODatabaseDocumentTx database) { + return new ONativeSynchQuery>( + database, CLASS_NAME, + new OQueryContextNativeSchema()) { + private static final long serialVersionUID = 1L; + + @Override + public boolean filter( + OQueryContextNativeSchema criteria) { + return criteria.field(ACCOUNT_ID).eq(account.getID()).go(); + }; + }; + } + + @Override + protected Mapper mapper() { + return mapper; + } + }); + } +} diff --git a/l2jserver2-loginserver/src/main/java/com/l2jserver/service/database/LoginServerJDBCDatabaseService.java b/l2jserver2-loginserver/src/main/java/com/l2jserver/service/database/LoginServerJDBCDatabaseService.java index 157ffb9ce..d1469efe8 100644 --- a/l2jserver2-loginserver/src/main/java/com/l2jserver/service/database/LoginServerJDBCDatabaseService.java +++ b/l2jserver2-loginserver/src/main/java/com/l2jserver/service/database/LoginServerJDBCDatabaseService.java @@ -18,7 +18,6 @@ package com.l2jserver.service.database; import java.sql.ResultSet; -import com.google.inject.Injector; import com.l2jserver.model.Model; import com.l2jserver.model.id.ID; import com.l2jserver.service.AbstractService.Depends; @@ -65,33 +64,19 @@ import com.l2jserver.service.core.threading.ThreadService; ConfigurationService.class, ThreadService.class }) public class LoginServerJDBCDatabaseService extends AbstractJDBCDatabaseService implements DatabaseService { - /** - * The Google Guice {@link Injector}. It is used to get DAO instances. - */ - @SuppressWarnings("unused") - private final Injector injector; - /** * @param configService * the config service - * @param injector - * the Guice {@link Injector} * @param cacheService * the cache service * @param threadService * the thread service + * @param daoResolver + * the {@link DataAccessObject DAO} resolver */ public LoginServerJDBCDatabaseService(ConfigurationService configService, - Injector injector, CacheService cacheService, - ThreadService threadService) { - super(configService, cacheService, threadService); - this.injector = injector; - } - - @Override - public , I extends ID> DataAccessObject getDAO( - Class model) { - // TODO - return null; + CacheService cacheService, ThreadService threadService, + DAOResolver daoResolver) { + super(configService, cacheService, threadService, daoResolver); } } diff --git a/pom.xml b/pom.xml index 7c92f8754..41fd3c6b3 100644 --- a/pom.xml +++ b/pom.xml @@ -102,9 +102,18 @@ src/assembly/distribution-mysql5-bin.xml src/assembly/distribution-h2-bin.xml + src/assembly/distribution-orientdb-bin.xml src/assembly/distribution-src.xml + + + package + + assembly + + + @@ -118,6 +127,137 @@ jar test + + + + org.jboss.netty + netty + 3.2.4.Final + runtime + + + + com.google.inject + guice + 3.0 + jar + runtime + + + com.google.inject.extensions + guice-assistedinject + 3.0 + jar + runtime + + + com.google.inject.extensions + guice-multibindings + 3.0 + jar + runtime + + + + org.slf4j + slf4j-log4j12 + 1.6.1 + jar + runtime + + + org.slf4j + jcl-over-slf4j + 1.6.1 + jar + runtime + + + + mysql + mysql-connector-java + 5.1.16 + compile + + + com.h2database + h2 + 1.3.155 + compile + + + commons-dbcp + commons-dbcp + 1.4 + jar + compile + + + + com.orientechnologies + orientdb-core + 1.0rc5 + compile + + + + net.sf.ehcache + ehcache-core + 2.4.2 + jar + runtime + + + + org.htmlparser + htmlparser + 2.1 + jar + runtime + + + + javolution + javolution + 5.5.1 + jar + runtime + + + com.google.guava + guava + r09 + jar + runtime + + + commons-io + commons-io + 2.0.1 + jar + runtime + + + commons-pool + commons-pool + 1.5.6 + jar + runtime + + + commons-collections + commons-collections + 3.2.1 + jar + runtime + + + org.apache.commons + commons-math + 2.2 + jar + runtime + @@ -136,8 +276,13 @@ default - EclipseLink Repo - http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo + orientechnologies-repository + Orient Technologies Maven2 Repository + http://www.orientechnologies.com/listing/m2 + + true + always +