mirror of
https://github.com/Rogiel/l2jserver2
synced 2025-12-05 23:22:47 +00:00
Modularizes the Maven project
This commit modularizes the maven project into several modules: - l2jserver2-common: common sources for both login and gameserver - l2jserver2-gameserver: the game server - l2jserver2-loginserver: the login server - l2jserver2-tools: refactored src/tools/java soure folder
This commit is contained in:
147
l2jserver2-common/pom.xml
Normal file
147
l2jserver2-common/pom.xml
Normal file
@@ -0,0 +1,147 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>l2jserver2</artifactId>
|
||||
<groupId>com.l2jserver</groupId>
|
||||
<version>2.0.0</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>l2jserver2-common</artifactId>
|
||||
<dependencies>
|
||||
<!-- junit -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.2</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- netty -->
|
||||
<dependency>
|
||||
<groupId>org.jboss.netty</groupId>
|
||||
<artifactId>netty</artifactId>
|
||||
<version>3.2.4.Final</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- google guice -->
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-assistedinject</artifactId>
|
||||
<version>3.0</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-multibindings</artifactId>
|
||||
<version>3.0</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- database -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.16</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.155</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
<version>1.4</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- cache -->
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>2.4.2</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- html parser/generator -->
|
||||
<dependency>
|
||||
<groupId>org.htmlparser</groupId>
|
||||
<artifactId>htmlparser</artifactId>
|
||||
<version>2.1</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- utils -->
|
||||
<dependency>
|
||||
<groupId>javolution</groupId>
|
||||
<artifactId>javolution</artifactId>
|
||||
<version>5.5.1</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>10.0</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-pool</groupId>
|
||||
<artifactId>commons-pool</artifactId>
|
||||
<version>1.5.6</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math</artifactId>
|
||||
<version>2.2</version>
|
||||
<type>jar</type>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.l2jserver.model.id.ID;
|
||||
|
||||
/**
|
||||
* Simple model interface implementing {@link ID} related methods
|
||||
*
|
||||
* @param <T>
|
||||
* the ID type used to represent this {@link Model}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class AbstractModel<T extends ID<?>> implements Model<T> {
|
||||
/**
|
||||
* The object id
|
||||
*/
|
||||
protected T id;
|
||||
/**
|
||||
* The database object state
|
||||
*/
|
||||
protected transient ObjectDesire desire = ObjectDesire.INSERT;
|
||||
|
||||
@Override
|
||||
public T getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setID(T ID) {
|
||||
Preconditions.checkState(id == null, "ID is already set");
|
||||
desireInsert();
|
||||
this.id = ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectDesire getObjectDesire() {
|
||||
return desire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObjectDesire(ObjectDesire desire) {
|
||||
if (desire == null)
|
||||
desire = ObjectDesire.NONE;
|
||||
this.desire = desire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this object desire to {@link ObjectDesire#UPDATE}. If the desire is
|
||||
* {@link ObjectDesire#INSERT} or {@link ObjectDesire#DELETE} the desire
|
||||
* will not be changed.
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
protected void desireUpdate() {
|
||||
if (this.desire != ObjectDesire.INSERT
|
||||
&& this.desire != ObjectDesire.DELETE)
|
||||
this.desire = ObjectDesire.UPDATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this object desire to {@link ObjectDesire#INSERT}. If the desire is
|
||||
* {@link ObjectDesire#DELETE} the desire will not be changed.
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
protected void desireInsert() {
|
||||
if (this.desire != ObjectDesire.DELETE)
|
||||
this.desire = ObjectDesire.INSERT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AbstractModel<?> other = (AbstractModel<?>) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
104
l2jserver2-common/src/main/java/com/l2jserver/model/Model.java
Normal file
104
l2jserver2-common/src/main/java/com/l2jserver/model/Model.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model;
|
||||
|
||||
import com.l2jserver.model.id.ID;
|
||||
import com.l2jserver.service.database.DatabaseService;
|
||||
|
||||
/**
|
||||
* Base model. Each object model must implement this interface to be able to be
|
||||
* inserted into the database.
|
||||
*
|
||||
* @param <T>
|
||||
* the {@link ID} type used to represent this {@link Model}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface Model<T extends ID<?>> {
|
||||
/**
|
||||
* @return the object ID
|
||||
*/
|
||||
T getID();
|
||||
|
||||
/**
|
||||
* Please note that the ID can only be set one time. Once it has been set,
|
||||
* it cannot be changed and a {@link IllegalStateException} will be thrown
|
||||
* if trying to change the ID.
|
||||
*
|
||||
* @param ID
|
||||
* the object ID to set
|
||||
* @throws IllegalStateException
|
||||
* if the ID was already set
|
||||
*/
|
||||
void setID(T ID) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Each object has an desire. Desires express what the
|
||||
* {@link DatabaseService} should do with the object. The service
|
||||
* automatically keep tracks of every database object (and release them when
|
||||
* they are garbage collected).
|
||||
*
|
||||
* @return the database object desire
|
||||
*/
|
||||
ObjectDesire getObjectDesire();
|
||||
|
||||
/**
|
||||
* Each object has an desire. Desires express what the
|
||||
* {@link DatabaseService} should do with the object. The service
|
||||
* automatically keep tracks of every database object (and release them when
|
||||
* they are garbage collected).
|
||||
*
|
||||
* @param desire
|
||||
* the database object desire to set
|
||||
*/
|
||||
void setObjectDesire(ObjectDesire desire);
|
||||
|
||||
/**
|
||||
* Indicated what the object wants to do in the database. It indicates
|
||||
* whether the object should be inserted, updated or deleted from the
|
||||
* database.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public enum ObjectDesire {
|
||||
/**
|
||||
* Don't do anything
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* Insert a new object into database.
|
||||
* <p>
|
||||
* If the primary key is auto generated by the database a clone of this
|
||||
* object will be created.<br>
|
||||
* If the primary key is <b>not</b> auto generated by the database, an
|
||||
* database exception will occur.
|
||||
*/
|
||||
INSERT,
|
||||
/**
|
||||
* Updates the object in the database.
|
||||
* <p>
|
||||
* If the object is not in the database nothing will happen.
|
||||
*/
|
||||
UPDATE,
|
||||
/**
|
||||
* Deletes the object from the database.
|
||||
* <p>
|
||||
* If tge object is not in the database nothing will happen.
|
||||
*/
|
||||
DELETE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id;
|
||||
|
||||
import com.l2jserver.model.Model;
|
||||
|
||||
/**
|
||||
* This is an abstract ID for most model objects.
|
||||
*
|
||||
* @param <T>
|
||||
* the raw id type
|
||||
* @param <O>
|
||||
* the model this {@link ID} provides
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class AbstractModelID<T, O extends Model<? extends ID<T>>>
|
||||
extends ID<T> {
|
||||
/**
|
||||
* @param id
|
||||
* the id
|
||||
*/
|
||||
protected AbstractModelID(T id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Model} object associated with this
|
||||
* {@link AbstractModelID}. <tt>null</tt> if {@link Model} does not
|
||||
* exists.
|
||||
*/
|
||||
public abstract O getObject();
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* The ID interface. Each object must be represented by an unique ID.
|
||||
*
|
||||
* @param <T>
|
||||
* the raw id type
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class ID<T> {
|
||||
/**
|
||||
* The id itself
|
||||
*/
|
||||
protected final T id;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the raw id
|
||||
*/
|
||||
@Inject
|
||||
protected ID(T id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public T getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + " [id=" + id + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + id.hashCode() + this.getClass().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
@SuppressWarnings("rawtypes")
|
||||
ID other = (ID) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.compound;
|
||||
|
||||
import com.l2jserver.model.id.ID;
|
||||
|
||||
/**
|
||||
* The compound {@link ID} is composed of two IDs.
|
||||
*
|
||||
* @param <T1>
|
||||
* the first {@link ID} type
|
||||
* @param <T2>
|
||||
* the second {@link ID} type
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class AbstractCompoundID<T1, T2> extends ID<AbstractCompoundID<T1, T2>> {
|
||||
/**
|
||||
* The first ID
|
||||
*/
|
||||
private final T1 id1;
|
||||
/**
|
||||
* The second ID
|
||||
*/
|
||||
private final T2 id2;
|
||||
|
||||
/**
|
||||
* Creates a new compound ID
|
||||
*
|
||||
* @param id1
|
||||
* the first id
|
||||
* @param id2
|
||||
* the second id
|
||||
*/
|
||||
protected AbstractCompoundID(T1 id1, T2 id2) {
|
||||
super(null);
|
||||
this.id1 = id1;
|
||||
this.id2 = id2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the first id
|
||||
*/
|
||||
public T1 getID1() {
|
||||
return id1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the second id
|
||||
*/
|
||||
public T2 getID2() {
|
||||
return id2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractCompoundID<T1, T2> getID() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.object.allocator;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.l2jserver.util.PrimeFinder;
|
||||
|
||||
/**
|
||||
* The {@link BitSet} id allocator allocates new IDs backed by an {@link BitSet}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class BitSetIDAllocator implements IDAllocator {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(BitSetIDAllocator.class);
|
||||
|
||||
/**
|
||||
* Lock to guarantee synchronization
|
||||
*/
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Available IDs
|
||||
*/
|
||||
private BitSet ids = new BitSet();
|
||||
/**
|
||||
* Amount of free ids
|
||||
*/
|
||||
private AtomicInteger freeIdCount = new AtomicInteger();
|
||||
/**
|
||||
* Next free ID
|
||||
*/
|
||||
private AtomicInteger nextId = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* Initializes this allocator
|
||||
*/
|
||||
public void init() {
|
||||
ids = new BitSet(PrimeFinder.nextPrime(100000));
|
||||
ids.clear();
|
||||
freeIdCount = new AtomicInteger(ALLOCABLE_IDS);
|
||||
|
||||
nextId = new AtomicInteger(ids.nextClearBit(0));
|
||||
log.info("BitSet IDAllocator initialized. Next available ID is {}",
|
||||
nextId.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void allocate(int id) {
|
||||
if (ids.get(id - FIRST_ID))
|
||||
throw new IDAllocatorException("ID not allocated");
|
||||
log.debug("Allocating ID {}", id);
|
||||
lock.lock();
|
||||
try {
|
||||
if (id < FIRST_ID)
|
||||
return;
|
||||
ids.set(id - FIRST_ID);
|
||||
nextId = new AtomicInteger(ids.nextClearBit(0));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int allocate() {
|
||||
lock.lock();
|
||||
try {
|
||||
final int newID = nextId.get();
|
||||
ids.set(newID);
|
||||
freeIdCount.decrementAndGet();
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Allocated a new ID {}", newID + FIRST_ID);
|
||||
|
||||
int nextFree = ids.nextClearBit(newID);
|
||||
|
||||
if (nextFree < 0) {
|
||||
nextFree = ids.nextClearBit(0);
|
||||
}
|
||||
if (nextFree < 0) {
|
||||
if (ids.size() < ALLOCABLE_IDS) {
|
||||
increaseBitSetCapacity();
|
||||
} else {
|
||||
log.error("ID exhaustion");
|
||||
throw new IDAllocatorException("ID exhaustion");
|
||||
}
|
||||
}
|
||||
|
||||
nextId.set(nextFree);
|
||||
return newID + FIRST_ID;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(int id) {
|
||||
if (id < FIRST_ID)
|
||||
throw new IDAllocatorException(
|
||||
"Can't release ID, smaller then initial ID");
|
||||
if (!ids.get(id - FIRST_ID))
|
||||
throw new IDAllocatorException("ID not allocated");
|
||||
|
||||
log.debug("Releasing allocated ID {}", id);
|
||||
lock.lock();
|
||||
try {
|
||||
ids.clear(id - FIRST_ID);
|
||||
freeIdCount.incrementAndGet();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
ids.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the {@link BitSet} capacity
|
||||
*/
|
||||
private void increaseBitSetCapacity() {
|
||||
log.debug("Increasing BitSet capacity from {}", ids.size());
|
||||
BitSet newBitSet = new BitSet(
|
||||
PrimeFinder.nextPrime((getAllocatedIDs() * 11) / 10));
|
||||
newBitSet.or(ids);
|
||||
ids = newBitSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAllocatedIDs() {
|
||||
return ALLOCABLE_IDS - getFreeIDs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFreeIDs() {
|
||||
return freeIdCount.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.object.allocator;
|
||||
|
||||
/**
|
||||
* The ID allocator is used to alloc new ID and to release IDs that aren't used
|
||||
* anymore.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface IDAllocator {
|
||||
/**
|
||||
* The first ID ever allocated
|
||||
*/
|
||||
public final static int FIRST_ID = 0x10000000;
|
||||
/**
|
||||
* The last ID ever allocated
|
||||
*/
|
||||
public final static int LAST_ID = 0x7FFFFFFF;
|
||||
/**
|
||||
* Total of available IDs for allocation
|
||||
*/
|
||||
public final static int ALLOCABLE_IDS = LAST_ID - FIRST_ID;
|
||||
|
||||
/**
|
||||
* This is method is used to register IDs as used at startup time.
|
||||
*
|
||||
* @param id
|
||||
* the id
|
||||
*/
|
||||
void allocate(int id);
|
||||
|
||||
/**
|
||||
* Allocates a new ID
|
||||
*
|
||||
* @return the allocated ID value
|
||||
*/
|
||||
int allocate();
|
||||
|
||||
/**
|
||||
* Release an ID
|
||||
*
|
||||
* @param id
|
||||
* the id
|
||||
*/
|
||||
void release(int id);
|
||||
|
||||
/**
|
||||
* Release all allocated IDs
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Get the amount of already allocated IDs
|
||||
*
|
||||
* @return allocated ids count
|
||||
*/
|
||||
int getAllocatedIDs();
|
||||
|
||||
/**
|
||||
* Get the amount of IDs remaining to be allocated
|
||||
*
|
||||
* @return free ids count
|
||||
*/
|
||||
int getFreeIDs();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.object.allocator;
|
||||
|
||||
/**
|
||||
* Exception thrown by an {@link IDAllocator}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class IDAllocatorException extends RuntimeException {
|
||||
/**
|
||||
* The Java Serialization Serial
|
||||
*/
|
||||
private static final long serialVersionUID = 111195059766878062L;
|
||||
|
||||
/**
|
||||
* Creates an empty instance of this exception
|
||||
*/
|
||||
public IDAllocatorException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public IDAllocatorException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public IDAllocatorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public IDAllocatorException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.provider;
|
||||
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.l2jserver.model.id.ID;
|
||||
import com.l2jserver.model.id.compound.AbstractCompoundID;
|
||||
|
||||
/**
|
||||
* The ID factory is used to create instances of IDs. It will automatically make
|
||||
* sure the ID is free before allocating it.
|
||||
*
|
||||
* @param <I1>
|
||||
* the first compound {@link ID} type
|
||||
* @param <I2>
|
||||
* the second compound {@link ID} type
|
||||
* @param <T>
|
||||
* the {@link CompoundIDProvider} type
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface CompoundIDProvider<I1 extends ID<?>, I2 extends ID<?>, T extends AbstractCompoundID<I1, I2>> {
|
||||
/**
|
||||
* Creates the ID object for an <b>EXISTING</b> ID.
|
||||
*
|
||||
* @param id1
|
||||
* the first id
|
||||
* @param id2
|
||||
* the second id
|
||||
* @return the created compound {@link ID}
|
||||
*/
|
||||
T createID(@Assisted("id1") I1 id1, @Assisted("id2") I2 id2);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.provider;
|
||||
|
||||
import com.l2jserver.model.id.ID;
|
||||
|
||||
/**
|
||||
* ID objects should never be directly instantiated and an provider
|
||||
* implementation must be used to create and generate them.
|
||||
* <p>
|
||||
*
|
||||
* The ID provider is used to create instances of IDs. It will automatically
|
||||
* make sure the ID is free before allocating it.
|
||||
* <p>
|
||||
* The provider will also make sure only a single instance for each raw ID
|
||||
* exits, that is for any given ID instance for raw value <b>1</b> only a single
|
||||
* object will be created and following calls will always return the same
|
||||
* object.
|
||||
*
|
||||
* @param <I>
|
||||
* the raw id type
|
||||
* @param <T>
|
||||
* the {@link ID} implementation
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface IDProvider<I, T extends ID<I>> {
|
||||
/**
|
||||
* Creates the ID object for an <b>EXISTING</b> ID.
|
||||
*
|
||||
* @param id
|
||||
* the raw id value
|
||||
* @return the resolved {@link ID} object
|
||||
*/
|
||||
T resolveID(I id);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An abstract service implementing basic life-cycle methods.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class AbstractService implements Service {
|
||||
/**
|
||||
* Running state of a service
|
||||
*/
|
||||
protected boolean running = false;
|
||||
|
||||
@Override
|
||||
public final void start() throws ServiceStartException {
|
||||
if (running)
|
||||
throw new ServiceStartException("Service is already started");
|
||||
try {
|
||||
this.doStart();
|
||||
this.running = true;
|
||||
} catch (ServiceStartException e) {
|
||||
this.running = false;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the service. This method is invoked internally by {@link #start()}
|
||||
*
|
||||
* @throws ServiceStartException
|
||||
* if any error occur while starting the service
|
||||
*/
|
||||
protected void doStart() throws ServiceStartException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void stop() throws ServiceStopException {
|
||||
if (!running)
|
||||
throw new ServiceStopException("Service is not started");
|
||||
try {
|
||||
this.doStop();
|
||||
} finally {
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service. This method is invoked internally by {@link #stop()}
|
||||
*
|
||||
* @throws ServiceStopException
|
||||
* if any error occur while stopping the service
|
||||
*/
|
||||
protected void doStop() throws ServiceStopException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restart() throws ServiceException {
|
||||
this.stop();
|
||||
this.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
return running;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStopped() {
|
||||
return !running;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Service>[] getDependencies() {
|
||||
final Depends deps = this.getClass().getAnnotation(Depends.class);
|
||||
if (deps == null)
|
||||
return null;
|
||||
return deps.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Service dependency metadata
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Depends {
|
||||
/**
|
||||
* @return the service's dependency
|
||||
*/
|
||||
Class<? extends Service>[] value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
/**
|
||||
* Each Service is a provider of a given feature. Most services will want to
|
||||
* implement {@link AbstractService} class instead of this interface.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface Service {
|
||||
/**
|
||||
* Start this service
|
||||
*
|
||||
* @throws ServiceStartException
|
||||
* if an error occurred
|
||||
*/
|
||||
void start() throws ServiceStartException;
|
||||
|
||||
/**
|
||||
* Stop this service
|
||||
*
|
||||
* @throws ServiceStopException
|
||||
* if an error occurred
|
||||
*/
|
||||
void stop() throws ServiceStopException;
|
||||
|
||||
/**
|
||||
* Stop this service
|
||||
*
|
||||
* @throws ServiceException
|
||||
* if an error occurred
|
||||
*/
|
||||
void restart() throws ServiceException;
|
||||
|
||||
/**
|
||||
* @return true if service is running
|
||||
*/
|
||||
boolean isStarted();
|
||||
|
||||
/**
|
||||
* @return false if service is not running
|
||||
*/
|
||||
boolean isStopped();
|
||||
|
||||
/**
|
||||
* @return the other services that the service depends on
|
||||
*/
|
||||
Class<? extends Service>[] getDependencies();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
import com.l2jserver.service.configuration.Configuration;
|
||||
|
||||
/**
|
||||
* Base interface for all {@link Service} {@link Configuration} classes.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface ServiceConfiguration extends Configuration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
import com.l2jserver.util.exception.L2Exception;
|
||||
|
||||
/**
|
||||
* Exception for an {@link Service}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class ServiceException extends L2Exception {
|
||||
/**
|
||||
* The Java Serialization API serial
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*/
|
||||
public ServiceException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public ServiceException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.l2jserver.service.core.LoggingService;
|
||||
import com.l2jserver.util.ClassUtils;
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
|
||||
/**
|
||||
* The {@link ServiceManager} is responsible for starting and stopping services
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ServiceManager {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger logger;
|
||||
/**
|
||||
* The Guice Injector
|
||||
*/
|
||||
private final Injector injector;
|
||||
/**
|
||||
* List of all known services by this manager
|
||||
*/
|
||||
private final Set<Service> knownServices = CollectionFactory.newSet();
|
||||
|
||||
/**
|
||||
* @param injector
|
||||
* the {@link Guice} {@link Injector}
|
||||
*/
|
||||
@Inject
|
||||
public ServiceManager(Injector injector) {
|
||||
this.injector = injector;
|
||||
final LoggingService service = injector
|
||||
.getInstance(LoggingService.class);
|
||||
knownServices.add(service);
|
||||
try {
|
||||
service.start();
|
||||
} catch (ServiceStartException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
logger = LoggerFactory.getLogger(ServiceManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* the service type
|
||||
* @param serviceClass
|
||||
* the service interface <tt>Class<T></tt>
|
||||
* @return the service implementation
|
||||
*/
|
||||
public <T extends Service> T get(Class<T> serviceClass) {
|
||||
return injector.getInstance(serviceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the given service implementation
|
||||
*
|
||||
* @param <T>
|
||||
* the service interface type
|
||||
* @param serviceClass
|
||||
* the service interface
|
||||
* @return the service implementation
|
||||
* @throws ServiceStartException
|
||||
* if any error occur while starting service
|
||||
*/
|
||||
public <T extends Service> T start(Class<T> serviceClass)
|
||||
throws ServiceStartException {
|
||||
final T service = injector.getInstance(serviceClass);
|
||||
if (service == null)
|
||||
return null;
|
||||
if (service.isStarted())
|
||||
return service;
|
||||
knownServices.add(service);
|
||||
try {
|
||||
startDependencies(service.getDependencies());
|
||||
logger.debug("{}: Starting service...",
|
||||
serviceClass.getSimpleName());
|
||||
service.start();
|
||||
logger.info("{} started", serviceClass.getSimpleName());
|
||||
return service;
|
||||
} catch (ServiceStartException e) {
|
||||
logger.error("{}: Error starting service: {}",
|
||||
serviceClass.getSimpleName(), e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.error("{}: Error starting service: {}",
|
||||
serviceClass.getSimpleName(), e);
|
||||
throw new ServiceStartException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the dependencies
|
||||
*
|
||||
* @param dependencies
|
||||
* the dependencies
|
||||
* @throws ServiceStartException
|
||||
* if any error occur while starting dependencies
|
||||
*/
|
||||
private void startDependencies(Class<? extends Service>[] dependencies)
|
||||
throws ServiceStartException {
|
||||
if (dependencies == null)
|
||||
return;
|
||||
if (dependencies.length == 0)
|
||||
return;
|
||||
for (final Class<? extends Service> serviceClass : dependencies) {
|
||||
this.start(serviceClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the given service implementation
|
||||
*
|
||||
* @param serviceClass
|
||||
* the service interface
|
||||
* @throws ServiceStopException
|
||||
* if any error occur while stopping service
|
||||
*/
|
||||
public void stop(Class<? extends Service> serviceClass)
|
||||
throws ServiceStopException {
|
||||
final Service service = injector.getInstance(serviceClass);
|
||||
if (service == null)
|
||||
return;
|
||||
if (service.isStopped())
|
||||
return;
|
||||
knownServices.add(service);
|
||||
try {
|
||||
logger.debug("{0}: Stopping service...",
|
||||
serviceClass.getSimpleName());
|
||||
stopDependencies(service);
|
||||
service.stop();
|
||||
logger.info("{0}: Service stopped!", serviceClass.getSimpleName());
|
||||
} catch (ServiceStopException e) {
|
||||
logger.error("{0}: Error stopping service: {1}",
|
||||
serviceClass.getSimpleName(), e.getCause());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the dependencies
|
||||
*
|
||||
* @param service
|
||||
* the service
|
||||
* @throws ServiceStopException
|
||||
* if any error occur while stopping dependencies
|
||||
*/
|
||||
private void stopDependencies(Service service) throws ServiceStopException {
|
||||
final Set<Class<? extends Service>> dependencies = createStopDependencies(
|
||||
null, service);
|
||||
for (final Class<? extends Service> dependency : dependencies) {
|
||||
this.stop(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Set} of all dependecies to be stopped
|
||||
*
|
||||
* @param depends
|
||||
* the service
|
||||
* @param serviceClass
|
||||
* the service class
|
||||
* @return the {@link Set} of all depedendecies to be stopped
|
||||
*/
|
||||
private Set<Class<? extends Service>> createStopDependencies(
|
||||
Set<Class<? extends Service>> depends, Service serviceClass) {
|
||||
if (depends == null)
|
||||
depends = CollectionFactory.newSet();
|
||||
for (final Service service : knownServices) {
|
||||
if (service.getDependencies() == null
|
||||
|| service.getDependencies().length == 0)
|
||||
continue;
|
||||
for (final Class<? extends Service> dependency : service
|
||||
.getDependencies()) {
|
||||
if (!ClassUtils.isSubclass(service.getClass(), dependency))
|
||||
continue;
|
||||
depends.add(dependency);
|
||||
createStopDependencies(depends,
|
||||
injector.getInstance(dependency));
|
||||
}
|
||||
}
|
||||
return depends;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the given service
|
||||
*
|
||||
* @param <T>
|
||||
* the service type
|
||||
* @param serviceClass
|
||||
* the service interface
|
||||
* @return the service implementation
|
||||
* @throws ServiceException
|
||||
* if any error occur while starting or stopping the service
|
||||
*/
|
||||
public <T extends Service> T restart(Class<T> serviceClass)
|
||||
throws ServiceException {
|
||||
final T service = injector.getInstance(serviceClass);
|
||||
if (service == null)
|
||||
return null;
|
||||
if (service.isStopped())
|
||||
throw new ServiceStopException("Service is already stopped");
|
||||
knownServices.add(service);
|
||||
try {
|
||||
logger.debug("{0}: Restaring service...",
|
||||
serviceClass.getSimpleName());
|
||||
service.restart();
|
||||
logger.info("{0}: Service restarted!", serviceClass.getSimpleName());
|
||||
return service;
|
||||
} catch (ServiceStartException e) {
|
||||
logger.error("{0}: Error starting service: {1}",
|
||||
serviceClass.getSimpleName(), e.getCause());
|
||||
throw e;
|
||||
} catch (ServiceStopException e) {
|
||||
logger.error("{0}: Error stopping service: {1}",
|
||||
serviceClass.getSimpleName(), e.getCause());
|
||||
throw e;
|
||||
} catch (ServiceException e) {
|
||||
logger.error("{0}: Error restarting service: {1}",
|
||||
serviceClass.getSimpleName(), e.getCause());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
/**
|
||||
* Thrown when an service failed to restart. It's <tt>cause</tt> can be an
|
||||
* {@link ServiceStartException} or {@link ServiceStopException}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ServiceRestartException extends ServiceException {
|
||||
/**
|
||||
* The Java Serialization API serial
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*/
|
||||
public ServiceRestartException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceRestartException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public ServiceRestartException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceRestartException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
/**
|
||||
* Exception thrown when a service failed to start.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ServiceStartException extends ServiceException {
|
||||
/**
|
||||
* The Java Serialization API serial
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*/
|
||||
public ServiceStartException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceStartException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public ServiceStartException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceStartException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service;
|
||||
|
||||
/**
|
||||
* Exception thrown when a service failed to stop
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ServiceStopException extends ServiceException {
|
||||
/**
|
||||
* The Java Serialization API serial
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*/
|
||||
public ServiceStopException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceStopException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public ServiceStopException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this exception
|
||||
*
|
||||
* @param cause
|
||||
* the root cause
|
||||
*/
|
||||
public ServiceStopException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
153
l2jserver2-common/src/main/java/com/l2jserver/service/cache/AbstractReferenceCache.java
vendored
Normal file
153
l2jserver2-common/src/main/java/com/l2jserver/service/cache/AbstractReferenceCache.java
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
|
||||
/**
|
||||
* Base class for weak caches and soft caches
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
*/
|
||||
abstract class AbstractReferenceCache<K, V> implements Cache<K, V> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The cache name
|
||||
*/
|
||||
protected final String cacheName;
|
||||
|
||||
/**
|
||||
* Map storing references to cached objects
|
||||
*/
|
||||
protected final Map<K, Reference<V>> cacheMap = CollectionFactory.newMap();
|
||||
/**
|
||||
* The reference queue
|
||||
*/
|
||||
protected final ReferenceQueue<V> refQueue = CollectionFactory
|
||||
.newReferenceQueue();
|
||||
|
||||
/**
|
||||
* @param cacheName
|
||||
* the cache name
|
||||
*/
|
||||
protected AbstractReferenceCache(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cleanQueue();
|
||||
|
||||
Reference<V> entry = newReference(key, value, refQueue);
|
||||
cacheMap.put(key, entry);
|
||||
|
||||
log.debug("{}: added for key: {}", cacheName, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
cleanQueue();
|
||||
|
||||
Reference<V> reference = cacheMap.get(key);
|
||||
if (reference == null)
|
||||
return null;
|
||||
|
||||
V res = reference.get();
|
||||
if (res != null)
|
||||
log.debug("{}: obtained for key: {}", cacheName, key);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(K key) {
|
||||
cleanQueue();
|
||||
return cacheMap.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the queue
|
||||
*/
|
||||
protected abstract void cleanQueue();
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
cacheMap.remove(key);
|
||||
log.debug("{}: removed for key: {}", cacheName, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
cacheMap.clear();
|
||||
log.debug("{}: cleared", cacheName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
cleanQueue();
|
||||
return new Iterator<V>() {
|
||||
private final Iterator<Reference<V>> iterator = cacheMap.values()
|
||||
.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V next() {
|
||||
return iterator.next().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new reference
|
||||
*
|
||||
* @param key
|
||||
* the reference key
|
||||
* @param value
|
||||
* the reference value
|
||||
* @param queue
|
||||
* the queue
|
||||
* @return the new reference
|
||||
*/
|
||||
protected abstract Reference<V> newReference(K key, V value,
|
||||
ReferenceQueue<V> queue);
|
||||
}
|
||||
73
l2jserver2-common/src/main/java/com/l2jserver/service/cache/Cache.java
vendored
Normal file
73
l2jserver2-common/src/main/java/com/l2jserver/service/cache/Cache.java
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
/**
|
||||
* This interface represents a Map structure for cache usage.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
*/
|
||||
public interface Cache<K, V> extends Iterable<V> {
|
||||
/**
|
||||
* Adds a pair <key,value> to cache.<br>
|
||||
* <br>
|
||||
*
|
||||
* <font color='red'><b>NOTICE:</b> </font> if there is already a value with
|
||||
* given id in the map, {@link IllegalArgumentException} will be thrown.
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @param value
|
||||
* the cache content value
|
||||
*/
|
||||
void put(K key, V value);
|
||||
|
||||
/**
|
||||
* Returns cached value correlated to given key.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @return the cached value for this key
|
||||
*/
|
||||
V get(K key);
|
||||
|
||||
/**
|
||||
* Checks whether this map contains a value related to given key.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @return true if key has an value
|
||||
*/
|
||||
boolean contains(K key);
|
||||
|
||||
/**
|
||||
* Removes an entry from the map, that has given key.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
*/
|
||||
void remove(K key);
|
||||
|
||||
/**
|
||||
* Clears this cache
|
||||
*/
|
||||
void clear();
|
||||
}
|
||||
110
l2jserver2-common/src/main/java/com/l2jserver/service/cache/CacheService.java
vendored
Normal file
110
l2jserver2-common/src/main/java/com/l2jserver/service/cache/CacheService.java
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import com.l2jserver.service.Service;
|
||||
|
||||
/**
|
||||
* This is an transparent Cache system. It proxies an interface implementing
|
||||
* {@link Cacheable}. Once the first call is done through the proxy, the result
|
||||
* is cached in the underlying cache engine. When the second and sucedind calls
|
||||
* are made the cache is looked up, if a match (method and arguments pair) is
|
||||
* found, this result is returned.
|
||||
* <p>
|
||||
* If you do not desire to cache an method, annotate it with
|
||||
* {@link IgnoreCaching}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface CacheService extends Service {
|
||||
/**
|
||||
* Decorates the <tt>instance</tt> with the cache. Note that
|
||||
* <tt>interfaceType</tt> must be an interface!
|
||||
*
|
||||
* @param <T>
|
||||
* the <tt>instance</tt> type
|
||||
* @param interfaceType
|
||||
* the interface type. Remember, this must be an interface!
|
||||
* @param instance
|
||||
* the instance implementing the interface
|
||||
* @return the cache-decorated object
|
||||
*/
|
||||
<T extends Cacheable> T decorate(Class<T> interfaceType, T instance);
|
||||
|
||||
/**
|
||||
* Creates a new cache with default configurations. Eviction mode is LRU
|
||||
* (Last Recently Used). The size is only a guarantee that you can store
|
||||
* <b>at least</b> <tt>n</tt> items.
|
||||
*
|
||||
* @param <K>
|
||||
* the cache key type
|
||||
* @param <V>
|
||||
* the cache value type
|
||||
* @param name
|
||||
* the cache name
|
||||
* @param size
|
||||
* the maximum cache size
|
||||
* @size the maximum cache size
|
||||
* @return the created cache
|
||||
*/
|
||||
<K, V> Cache<K, V> createCache(String name, int size);
|
||||
|
||||
/**
|
||||
* Creates a new eternal cache with default configurations. An eternal cache
|
||||
* is guaranteed to never automatically expire items. The size is only a
|
||||
* guarantee that you can store <b>at least</b> <tt>n</tt> items.
|
||||
*
|
||||
* @param <K>
|
||||
* the cache key type
|
||||
* @param <V>
|
||||
* the cache value type
|
||||
* @param name
|
||||
* the cache name
|
||||
* @param size
|
||||
* the maximum cache size
|
||||
* @size the maximum cache size
|
||||
* @return the created cache
|
||||
*/
|
||||
<K, V> Cache<K, V> createEternalCache(String name, int size);
|
||||
|
||||
/**
|
||||
* Creates a new cache with default configurations. The default cache size
|
||||
* is 200. The size is only a guarantee that you can store <b>at least</b>
|
||||
* 200 items.
|
||||
*
|
||||
* @param <K>
|
||||
* the cache key type
|
||||
* @param <V>
|
||||
* the cache value type
|
||||
* @param name
|
||||
* the cache name
|
||||
* @return the created cache
|
||||
*/
|
||||
<K, V> Cache<K, V> createCache(String name);
|
||||
|
||||
/**
|
||||
* Disposes the cache. Once the cache is disposed it cannot be used anymore.
|
||||
*
|
||||
* @param <K>
|
||||
* the cache key type
|
||||
* @param <V>
|
||||
* the cache value type
|
||||
* @param cache
|
||||
* the cache
|
||||
*/
|
||||
<K, V> void dispose(Cache<K, V> cache);
|
||||
}
|
||||
29
l2jserver2-common/src/main/java/com/l2jserver/service/cache/Cacheable.java
vendored
Normal file
29
l2jserver2-common/src/main/java/com/l2jserver/service/cache/Cacheable.java
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
/**
|
||||
* Flags an interface that is capable of caching.
|
||||
* <p>
|
||||
* <b>Note</b>: only interfaces can be cached!
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface Cacheable {
|
||||
|
||||
}
|
||||
224
l2jserver2-common/src/main/java/com/l2jserver/service/cache/EhCacheService.java
vendored
Normal file
224
l2jserver2-common/src/main/java/com/l2jserver/service/cache/EhCacheService.java
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Element;
|
||||
import net.sf.ehcache.config.CacheConfiguration;
|
||||
import net.sf.ehcache.config.Configuration;
|
||||
import net.sf.ehcache.config.DiskStoreConfiguration;
|
||||
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
|
||||
/**
|
||||
* Simple cache that stores invocation results in a EhCache
|
||||
* {@link net.sf.ehcache.Cache Cache}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class EhCacheService extends AbstractService implements CacheService {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The cache manager
|
||||
*/
|
||||
private CacheManager manager;
|
||||
/**
|
||||
* The interface cache
|
||||
*/
|
||||
private Cache<MethodInvocation, Object> interfaceCache;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
manager = new CacheManager(new Configuration().updateCheck(false)
|
||||
.diskStore(new DiskStoreConfiguration().path("data/cache")));
|
||||
interfaceCache = createCache("interface-cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Cacheable> T decorate(final Class<T> interfaceType,
|
||||
final T instance) {
|
||||
Preconditions.checkNotNull(interfaceType, "interfaceType");
|
||||
Preconditions.checkNotNull(instance, "instance");
|
||||
Preconditions.checkArgument(interfaceType.isInterface(),
|
||||
"interfaceType is not an interface");
|
||||
|
||||
log.debug("Decorating {} with cache", interfaceType);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final T proxy = (T) Proxy.newProxyInstance(this.getClass()
|
||||
.getClassLoader(), new Class[] { interfaceType },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method,
|
||||
Object[] args) throws Throwable {
|
||||
if (method.isAnnotationPresent(IgnoreCaching.class))
|
||||
return method.invoke(instance, args);
|
||||
final MethodInvocation invocation = new MethodInvocation(
|
||||
method, args);
|
||||
Object result = interfaceCache.get(invocation);
|
||||
if (result == null)
|
||||
return doInvoke(invocation, proxy, method, args);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object doInvoke(MethodInvocation invocation,
|
||||
Object proxy, Method method, Object[] args)
|
||||
throws IllegalArgumentException,
|
||||
IllegalAccessException, InvocationTargetException {
|
||||
Object result = method.invoke(instance, args);
|
||||
interfaceCache.put(invocation, result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createCache(String name, int size) {
|
||||
Preconditions.checkNotNull(name, "name");
|
||||
Preconditions.checkArgument(size > 0, "size <= 0");
|
||||
|
||||
log.debug("Creating cache {} with minimum size of {}", name, size);
|
||||
|
||||
net.sf.ehcache.Cache cache = new net.sf.ehcache.Cache(
|
||||
new CacheConfiguration(name, size)
|
||||
.memoryStoreEvictionPolicy(
|
||||
MemoryStoreEvictionPolicy.LRU)
|
||||
.overflowToDisk(true).eternal(false)
|
||||
.timeToLiveSeconds(60).timeToIdleSeconds(30)
|
||||
.diskPersistent(false)
|
||||
.diskExpiryThreadIntervalSeconds(0));
|
||||
manager.addCache(cache);
|
||||
return new EhCacheFacade<K, V>(cache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createEternalCache(String name, int size) {
|
||||
Preconditions.checkNotNull(name, "name");
|
||||
Preconditions.checkArgument(size > 0, "size <= 0");
|
||||
|
||||
log.debug("Creating eternal cache {} with minimum size of {}", name,
|
||||
size);
|
||||
|
||||
net.sf.ehcache.Cache cache = new net.sf.ehcache.Cache(
|
||||
new CacheConfiguration(name, size)
|
||||
.memoryStoreEvictionPolicy(
|
||||
MemoryStoreEvictionPolicy.LRU)
|
||||
.overflowToDisk(true).eternal(true)
|
||||
.diskExpiryThreadIntervalSeconds(0));
|
||||
manager.addCache(cache);
|
||||
return new EhCacheFacade<K, V>(cache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createCache(String name) {
|
||||
return createCache(name, 200);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> void dispose(Cache<K, V> cache) {
|
||||
if (cache instanceof EhCacheFacade) {
|
||||
log.debug("Disposing cache {}", cache);
|
||||
manager.removeCache(((EhCacheFacade<K, V>) cache).cache.getName());
|
||||
} else {
|
||||
log.warn("Trying to dispose {} cache when it is not EhCacheFacade type");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ServiceStopException {
|
||||
manager.removalAll();
|
||||
manager.shutdown();
|
||||
interfaceCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link net.sf.ehcache.Cache EhCache} facade
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
*/
|
||||
private class EhCacheFacade<K, V> implements Cache<K, V> {
|
||||
/**
|
||||
* The backing cache
|
||||
*/
|
||||
private final net.sf.ehcache.Cache cache;
|
||||
|
||||
/**
|
||||
* @param cache
|
||||
* the backing cache
|
||||
*/
|
||||
public EhCacheFacade(net.sf.ehcache.Cache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(new Element(key, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public V get(K key) {
|
||||
final Element element = cache.get(key);
|
||||
if (element == null)
|
||||
return null;
|
||||
return (V) element.getObjectValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(K key) {
|
||||
return cache.get(key) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
cache.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
cache.removeAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
97
l2jserver2-common/src/main/java/com/l2jserver/service/cache/EternalCache.java
vendored
Normal file
97
l2jserver2-common/src/main/java/com/l2jserver/service/cache/EternalCache.java
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
|
||||
/**
|
||||
* Cache class for an eternal cache. Entries in this cache instance won't ever
|
||||
* be automatically removed, even if the JVM is running out of memory.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
*/
|
||||
public class EternalCache<K, V> implements Cache<K, V> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
protected final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The cache name
|
||||
*/
|
||||
protected final String cacheName;
|
||||
|
||||
/**
|
||||
* Map storing references to cached objects
|
||||
*/
|
||||
protected final Map<K, V> cacheMap = CollectionFactory.newMap();
|
||||
|
||||
/**
|
||||
* @param cacheName
|
||||
* the cache name
|
||||
*/
|
||||
protected EternalCache(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cacheMap.put(key, value);
|
||||
log.debug("{}: added for key: {}", cacheName, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
V obj = cacheMap.get(key);
|
||||
if (obj != null)
|
||||
log.debug("{}: obtained for key: {}", cacheName, key);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(K key) {
|
||||
return cacheMap.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
cacheMap.remove(key);
|
||||
log.debug("{}: removed for key: {}", cacheName, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
cacheMap.clear();
|
||||
log.debug("{}: cleared", cacheName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return cacheMap.values().iterator();
|
||||
}
|
||||
}
|
||||
34
l2jserver2-common/src/main/java/com/l2jserver/service/cache/IgnoreCaching.java
vendored
Normal file
34
l2jserver2-common/src/main/java/com/l2jserver/service/cache/IgnoreCaching.java
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicate to the proxy that this method should not be cached.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface IgnoreCaching {
|
||||
}
|
||||
75
l2jserver2-common/src/main/java/com/l2jserver/service/cache/MethodInvocation.java
vendored
Normal file
75
l2jserver2-common/src/main/java/com/l2jserver/service/cache/MethodInvocation.java
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Simple class used to store method invocations for the proxied cache.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
class MethodInvocation {
|
||||
/**
|
||||
* The invoked method
|
||||
*/
|
||||
private final Method method;
|
||||
/**
|
||||
* The invocation arguments
|
||||
*/
|
||||
private final Object[] args;
|
||||
|
||||
/**
|
||||
* @param method
|
||||
* the method invoked
|
||||
* @param args
|
||||
* the invocation arguments
|
||||
*/
|
||||
public MethodInvocation(Method method, Object[] args) {
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(args);
|
||||
result = prime * result + ((method == null) ? 0 : method.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
MethodInvocation other = (MethodInvocation) obj;
|
||||
if (!Arrays.equals(args, other.args))
|
||||
return false;
|
||||
if (method == null) {
|
||||
if (other.method != null)
|
||||
return false;
|
||||
} else if (!method.equals(other.method))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
200
l2jserver2-common/src/main/java/com/l2jserver/service/cache/SoftCacheService.java
vendored
Normal file
200
l2jserver2-common/src/main/java/com/l2jserver/service/cache/SoftCacheService.java
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
|
||||
/**
|
||||
* This {@link Cache} service implementation uses a {@link SoftReference} to
|
||||
* store values.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class SoftCacheService extends AbstractService implements CacheService {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The interface cache
|
||||
*/
|
||||
private Cache<MethodInvocation, Object> interfaceCache;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
interfaceCache = createCache("interface-cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Cacheable> T decorate(final Class<T> interfaceType,
|
||||
final T instance) {
|
||||
Preconditions.checkNotNull(interfaceType, "interfaceType");
|
||||
Preconditions.checkNotNull(instance, "instance");
|
||||
Preconditions.checkArgument(interfaceType.isInterface(),
|
||||
"interfaceType is not an interface");
|
||||
|
||||
log.debug("Decorating {} with cache", interfaceType);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final T proxy = (T) Proxy.newProxyInstance(this.getClass()
|
||||
.getClassLoader(), new Class[] { interfaceType },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method,
|
||||
Object[] args) throws Throwable {
|
||||
if (method.isAnnotationPresent(IgnoreCaching.class))
|
||||
return method.invoke(instance, args);
|
||||
final MethodInvocation invocation = new MethodInvocation(
|
||||
method, args);
|
||||
Object result = interfaceCache.get(invocation);
|
||||
if (result == null)
|
||||
return doInvoke(invocation, proxy, method, args);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object doInvoke(MethodInvocation invocation,
|
||||
Object proxy, Method method, Object[] args)
|
||||
throws IllegalArgumentException,
|
||||
IllegalAccessException, InvocationTargetException {
|
||||
Object result = method.invoke(instance, args);
|
||||
interfaceCache.put(invocation, result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createCache(String name, int size) {
|
||||
log.debug("Creating cache {} with minimum size of {}", name, size);
|
||||
return new SoftCache<K, V>(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createEternalCache(String name, int size) {
|
||||
log.debug("Creating eternal cache {} with minimum size of {}", name,
|
||||
size);
|
||||
return new EternalCache<K, V>(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createCache(String name) {
|
||||
return createCache(name, 200);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> void dispose(Cache<K, V> cache) {
|
||||
log.debug("Disposing {}", cache);
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ServiceStopException {
|
||||
dispose(interfaceCache);
|
||||
interfaceCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a simple map implementation for cache usage.<br>
|
||||
* <br>
|
||||
* Value may be stored in map really long, but it for sure will be removed
|
||||
* if there is low memory (and of course there isn't any strong reference to
|
||||
* value object)
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
*/
|
||||
private class SoftCache<K, V> extends AbstractReferenceCache<K, V>
|
||||
implements Cache<K, V> {
|
||||
/**
|
||||
* This class is a {@link SoftReference} with additional responsibility
|
||||
* of holding key object
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
private class SoftEntry extends SoftReference<V> {
|
||||
/**
|
||||
* The key
|
||||
*/
|
||||
private K key;
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key
|
||||
* @param referent
|
||||
* the value
|
||||
* @param q
|
||||
* the queue
|
||||
*/
|
||||
SoftEntry(K key, V referent, ReferenceQueue<? super V> q) {
|
||||
super(referent, q);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
K getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cacheName
|
||||
* the cache name
|
||||
*/
|
||||
public SoftCache(String cacheName) {
|
||||
super(cacheName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected synchronized void cleanQueue() {
|
||||
SoftEntry en = null;
|
||||
while ((en = (SoftEntry) refQueue.poll()) != null) {
|
||||
K key = en.getKey();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("{} : cleaned up {} for key: {}", cacheName, key);
|
||||
cacheMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Reference<V> newReference(K key, V value,
|
||||
ReferenceQueue<V> vReferenceQueue) {
|
||||
return new SoftEntry(key, value, vReferenceQueue);
|
||||
}
|
||||
}
|
||||
}
|
||||
199
l2jserver2-common/src/main/java/com/l2jserver/service/cache/WeakCacheService.java
vendored
Normal file
199
l2jserver2-common/src/main/java/com/l2jserver/service/cache/WeakCacheService.java
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
|
||||
/**
|
||||
* This {@link Cache} service implementation uses a {@link WeakReference} to
|
||||
* store values.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class WeakCacheService extends AbstractService implements CacheService {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The interface cache
|
||||
*/
|
||||
private Cache<MethodInvocation, Object> interfaceCache;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
interfaceCache = createCache("interface-cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Cacheable> T decorate(final Class<T> interfaceType,
|
||||
final T instance) {
|
||||
Preconditions.checkNotNull(interfaceType, "interfaceType");
|
||||
Preconditions.checkNotNull(instance, "instance");
|
||||
Preconditions.checkArgument(interfaceType.isInterface(),
|
||||
"interfaceType is not an interface");
|
||||
|
||||
log.debug("Decorating {} with cache", interfaceType);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final T proxy = (T) Proxy.newProxyInstance(this.getClass()
|
||||
.getClassLoader(), new Class[] { interfaceType },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method,
|
||||
Object[] args) throws Throwable {
|
||||
if (method.isAnnotationPresent(IgnoreCaching.class))
|
||||
return method.invoke(instance, args);
|
||||
final MethodInvocation invocation = new MethodInvocation(
|
||||
method, args);
|
||||
Object result = interfaceCache.get(invocation);
|
||||
if (result == null)
|
||||
return doInvoke(invocation, proxy, method, args);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object doInvoke(MethodInvocation invocation,
|
||||
Object proxy, Method method, Object[] args)
|
||||
throws IllegalArgumentException,
|
||||
IllegalAccessException, InvocationTargetException {
|
||||
Object result = method.invoke(instance, args);
|
||||
interfaceCache.put(invocation, result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createCache(String name, int size) {
|
||||
log.debug("Creating cache {} with minimum size of {}", name, size);
|
||||
return new WeakCache<K, V>(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createEternalCache(String name, int size) {
|
||||
log.debug("Creating eternal cache {} with minimum size of {}", name,
|
||||
size);
|
||||
return new EternalCache<K, V>(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Cache<K, V> createCache(String name) {
|
||||
return createCache(name, 200);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> void dispose(Cache<K, V> cache) {
|
||||
log.debug("Disposing {}", cache);
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ServiceStopException {
|
||||
dispose(interfaceCache);
|
||||
interfaceCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a simple map implementation for cache usage.<br>
|
||||
* <br>
|
||||
* Values from the map will be removed after the first garbage collector run
|
||||
* if there isn't any strong reference to the value object.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
*/
|
||||
private class WeakCache<K, V> extends AbstractReferenceCache<K, V>
|
||||
implements Cache<K, V> {
|
||||
/**
|
||||
* This class is a {@link WeakReference} with additional responsibility
|
||||
* of holding key object
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
private class Entry extends WeakReference<V> {
|
||||
/**
|
||||
* The key
|
||||
*/
|
||||
private K key;
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key
|
||||
* @param referent
|
||||
* the value
|
||||
* @param q
|
||||
* the queue
|
||||
*/
|
||||
Entry(K key, V referent, ReferenceQueue<? super V> q) {
|
||||
super(referent, q);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
K getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cacheName
|
||||
* the cache name
|
||||
*/
|
||||
WeakCache(String cacheName) {
|
||||
super(cacheName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected synchronized void cleanQueue() {
|
||||
Entry en = null;
|
||||
while ((en = (Entry) refQueue.poll()) != null) {
|
||||
K key = en.getKey();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("{}: cleaned up for key: {}", cacheName, key);
|
||||
cacheMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Reference<V> newReference(K key, V value,
|
||||
ReferenceQueue<V> vReferenceQueue) {
|
||||
return new Entry(key, value, vReferenceQueue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.configuration;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.l2jserver.service.configuration.ProxyConfigurationService.ConfigurationName;
|
||||
|
||||
/**
|
||||
* Configuration interface
|
||||
* <p>
|
||||
* Each service desiring to use the configuration system must extend the
|
||||
* interface and define methods for getters and setters. Each method must be
|
||||
* annotated either with {@link ConfigurationPropertyGetter} or
|
||||
* {@link ConfigurationPropertySetter}
|
||||
* <p>
|
||||
* Each interface may optionally be annotated with {@link ConfigurationName}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface Configuration {
|
||||
/**
|
||||
* The getter method for an configuration property
|
||||
* <p>
|
||||
* The method must have no arguments.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = ElementType.METHOD)
|
||||
public @interface ConfigurationPropertyGetter {
|
||||
/**
|
||||
* @return the default value to be used
|
||||
*/
|
||||
String defaultValue() default "";
|
||||
}
|
||||
|
||||
/**
|
||||
* The setter method for an configuration property.
|
||||
* <p>
|
||||
* The method must have a single argument and return type void.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = ElementType.METHOD)
|
||||
public @interface ConfigurationPropertySetter {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.configuration;
|
||||
|
||||
import com.l2jserver.service.Service;
|
||||
|
||||
/**
|
||||
* The configuration service is responsible for reading and writing in
|
||||
* configuration storage. Each configuration is represented by an interface.
|
||||
* Implementations of this interface are implementaion specific.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface ConfigurationService extends Service {
|
||||
/**
|
||||
* Get the configuration object for <tt>config</tt>
|
||||
*
|
||||
* @param <C>
|
||||
* the configuration type
|
||||
* @param config
|
||||
* the configuration interface class
|
||||
* @return the configuration object
|
||||
*/
|
||||
<C extends Configuration> C get(Class<C> config);
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.AbstractService.Depends;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.cache.CacheService;
|
||||
import com.l2jserver.service.configuration.Configuration.ConfigurationPropertyGetter;
|
||||
import com.l2jserver.service.configuration.Configuration.ConfigurationPropertySetter;
|
||||
import com.l2jserver.service.core.LoggingService;
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
import com.l2jserver.util.transformer.TransformerFactory;
|
||||
|
||||
/**
|
||||
* Creates {@link Configuration} object through Java {@link Proxy}. Uses the
|
||||
* annotations in the interface to retrieve and store values.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@Depends({ LoggingService.class, CacheService.class })
|
||||
public class ProxyConfigurationService extends AbstractService implements
|
||||
ConfigurationService {
|
||||
/**
|
||||
* The directory in which configuration files are stored
|
||||
*/
|
||||
private final File directory = new File("./config/properties");
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The cache of configuration objects
|
||||
*/
|
||||
private Map<Class<?>, Object> cache = CollectionFactory.newWeakMap();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Target(value = ElementType.METHOD)
|
||||
public @interface ConfigurationPropertiesKey {
|
||||
String value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Each configuration can define the name of its configuration. This will be
|
||||
* used by implementations to look for the configuration.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Target(value = ElementType.TYPE)
|
||||
public @interface ConfigurationName {
|
||||
/**
|
||||
* @return the configuration name
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
if (!directory.exists())
|
||||
if (!directory.mkdirs())
|
||||
throw new ServiceStartException("Failed to create directories");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends Configuration> C get(Class<C> config) {
|
||||
Preconditions.checkNotNull(config, "config");
|
||||
|
||||
if (cache.containsKey(config))
|
||||
return (C) cache.get(config);
|
||||
log.debug("Trying to create {} proxy", config);
|
||||
Properties properties;
|
||||
try {
|
||||
properties = findProperties(config);
|
||||
} catch (IOException e) {
|
||||
properties = new Properties();
|
||||
log.warn(
|
||||
"Configuration file for {} not found, falling back to default values",
|
||||
config);
|
||||
}
|
||||
C proxy = (C) Proxy.newProxyInstance(this.getClass().getClassLoader(),
|
||||
new Class<?>[] { config }, new ConfigInvocationHandler(
|
||||
properties));
|
||||
cache.put(config, proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* The invocation handler for configuration interfaces
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
private class ConfigInvocationHandler implements InvocationHandler {
|
||||
/**
|
||||
* The invocation handler properties
|
||||
*/
|
||||
private final Properties properties;
|
||||
/**
|
||||
* The invocation cache
|
||||
*/
|
||||
private Map<String, Object> cache = CollectionFactory.newWeakMap();
|
||||
|
||||
/**
|
||||
* @param properties
|
||||
* the properties
|
||||
*/
|
||||
public ConfigInvocationHandler(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
log.debug("Configuration service, method invoked: {}",
|
||||
method.getName());
|
||||
if (args == null || args.length == 0) {
|
||||
final ConfigurationPropertyGetter getter = method
|
||||
.getAnnotation(ConfigurationPropertyGetter.class);
|
||||
final ConfigurationPropertiesKey propertiesKey = method
|
||||
.getAnnotation(ConfigurationPropertiesKey.class);
|
||||
if (getter == null)
|
||||
return null;
|
||||
if (propertiesKey == null)
|
||||
return null;
|
||||
return get(getter, propertiesKey, method.getReturnType());
|
||||
} else if (args.length == 1) {
|
||||
final ConfigurationPropertySetter setter = method
|
||||
.getAnnotation(ConfigurationPropertySetter.class);
|
||||
final ConfigurationPropertiesKey propertiesKey = method
|
||||
.getAnnotation(ConfigurationPropertiesKey.class);
|
||||
if (setter == null)
|
||||
return null;
|
||||
if (propertiesKey == null)
|
||||
return null;
|
||||
set(propertiesKey, args[0], method.getParameterTypes()[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the untransformed value of an property
|
||||
*
|
||||
* @param getter
|
||||
* the getter annotation
|
||||
* @param propertiesKey
|
||||
* if properties key annotation
|
||||
* @param type
|
||||
* the transformed type
|
||||
* @return the untransformed property
|
||||
*/
|
||||
private Object get(ConfigurationPropertyGetter getter,
|
||||
ConfigurationPropertiesKey propertiesKey, Class<?> type) {
|
||||
if (cache.containsKey(propertiesKey.value()))
|
||||
return cache.get(propertiesKey.value());
|
||||
Object o = untransform(
|
||||
getRaw(propertiesKey.value(), getter.defaultValue()), type);
|
||||
cache.put(propertiesKey.value(), o);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transformed value of an property
|
||||
*
|
||||
* @param setter
|
||||
* the setter annotation
|
||||
* @param value
|
||||
* the untransformed value
|
||||
* @param type
|
||||
* the transformed type
|
||||
*/
|
||||
private void set(ConfigurationPropertiesKey setter, Object value,
|
||||
Class<?> type) {
|
||||
if (value != null) {
|
||||
properties.setProperty(setter.value(),
|
||||
transform(value.toString(), type));
|
||||
cache.remove(setter.value());
|
||||
} else {
|
||||
properties.remove(setter.value());
|
||||
cache.remove(setter.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Untransforms an value
|
||||
*
|
||||
* @param value
|
||||
* the raw value
|
||||
* @param type
|
||||
* the output type
|
||||
* @return the untransformed value
|
||||
*/
|
||||
private Object untransform(String value, Class<?> type) {
|
||||
if (value == null)
|
||||
return null;
|
||||
if (type == String.class)
|
||||
return value;
|
||||
final Transformer<?> transformer = TransformerFactory
|
||||
.getTransfromer(type);
|
||||
if (transformer == null)
|
||||
return null;
|
||||
return transformer.untransform(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an value
|
||||
*
|
||||
* @param value
|
||||
* the raw typed value
|
||||
* @param type
|
||||
* the input type
|
||||
* @return the string representing <tt>value</tt>
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private String transform(Object value, Class<?> type) {
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value instanceof String)
|
||||
return (String) value;
|
||||
final Transformer transformer = TransformerFactory
|
||||
.getTransfromer(type);
|
||||
if (transformer == null)
|
||||
return null;
|
||||
return transformer.transform(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw value from the property file
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param defaultValue
|
||||
* the default value
|
||||
* @return the value found or default value
|
||||
*/
|
||||
private String getRaw(String key, String defaultValue) {
|
||||
if (properties == null)
|
||||
return defaultValue;
|
||||
if (properties.containsKey(key)) {
|
||||
return (String) properties.get(key);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to locate an .properties file
|
||||
*
|
||||
* @param clazz
|
||||
* configuration interface class
|
||||
* @return the found property
|
||||
* @throws IOException
|
||||
* if any i/o error occur
|
||||
*/
|
||||
private Properties findProperties(Class<?> clazz) throws IOException {
|
||||
Preconditions.checkNotNull(clazz, "clazz");
|
||||
|
||||
ConfigurationName config = findAnnotation(ConfigurationName.class,
|
||||
clazz);
|
||||
Properties prop;
|
||||
if (config == null) {
|
||||
for (final Class<?> parent : clazz.getInterfaces()) {
|
||||
prop = findProperties(parent);
|
||||
if (prop != null)
|
||||
return prop;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
prop = new Properties();
|
||||
final File file = new File(directory, config.value() + ".properties");
|
||||
final InputStream in = new FileInputStream(file);
|
||||
try {
|
||||
prop.load(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find an annotation in the class or any parent-class.
|
||||
*
|
||||
* @param <T>
|
||||
* the annotation type
|
||||
* @param annotationClass
|
||||
* the annotation class
|
||||
* @param clazz
|
||||
* the class to look for annotations
|
||||
* @return the annotation found
|
||||
*/
|
||||
private <T extends Annotation> T findAnnotation(Class<T> annotationClass,
|
||||
Class<?> clazz) {
|
||||
Preconditions.checkNotNull(annotationClass, "annotationClass");
|
||||
Preconditions.checkNotNull(clazz, "clazz");
|
||||
|
||||
T ann = clazz.getAnnotation(annotationClass);
|
||||
if (ann != null)
|
||||
return ann;
|
||||
|
||||
for (Class<?> clazz2 : annotationClass.getInterfaces()) {
|
||||
if (clazz2 == clazz)
|
||||
continue;
|
||||
ann = findAnnotation(annotationClass, clazz2);
|
||||
if (ann != null)
|
||||
return ann;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configuration store directory
|
||||
*/
|
||||
public File getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.inject.Inject;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.AbstractService.Depends;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.cache.CacheService;
|
||||
import com.l2jserver.service.configuration.Configuration.ConfigurationPropertyGetter;
|
||||
import com.l2jserver.service.core.LoggingService;
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
import com.l2jserver.util.transformer.TransformerFactory;
|
||||
|
||||
/**
|
||||
* Creates {@link Configuration} object through Java {@link Proxy}. Uses the
|
||||
* annotations in the interface to retrieve and store values.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@Depends({ LoggingService.class, CacheService.class })
|
||||
public class XMLConfigurationService extends AbstractService implements
|
||||
ConfigurationService {
|
||||
/**
|
||||
* The directory in which configuration files are stored
|
||||
*/
|
||||
private File file = new File("./config/config.xml");
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The DOM {@link DocumentBuilderFactory}
|
||||
*/
|
||||
private DocumentBuilderFactory factory;
|
||||
/**
|
||||
* The DOM {@link DocumentBuilder}
|
||||
*/
|
||||
private DocumentBuilder builder;
|
||||
|
||||
private Document properties;
|
||||
|
||||
/**
|
||||
* The cache of configuration objects
|
||||
*/
|
||||
private Map<Class<?>, Object> cache = CollectionFactory.newWeakMap();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ConfigurationXPath {
|
||||
String value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty instance
|
||||
*/
|
||||
@Inject
|
||||
protected XMLConfigurationService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new service instance. <b>This is used for tests</b>
|
||||
*
|
||||
* @param file
|
||||
* the configuration file
|
||||
*/
|
||||
protected XMLConfigurationService(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
factory = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
builder = factory.newDocumentBuilder();
|
||||
properties = builder.parse(file);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ServiceStartException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new ServiceStartException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ServiceStartException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends Configuration> C get(Class<C> config) {
|
||||
Preconditions.checkNotNull(config, "config");
|
||||
|
||||
if (cache.containsKey(config))
|
||||
return (C) cache.get(config);
|
||||
log.debug("Trying to create {} proxy", config);
|
||||
|
||||
C proxy = (C) Proxy.newProxyInstance(this.getClass().getClassLoader(),
|
||||
new Class<?>[] { config }, new ConfigInvocationHandler(
|
||||
properties));
|
||||
cache.put(config, proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* The invocation handler for configuration interfaces
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
private class ConfigInvocationHandler implements InvocationHandler {
|
||||
/**
|
||||
* The invocation handler properties
|
||||
*/
|
||||
private final Document properties;
|
||||
/**
|
||||
* The invocation cache
|
||||
*/
|
||||
private Map<String, Object> cache = CollectionFactory.newWeakMap();
|
||||
|
||||
/**
|
||||
* @param properties
|
||||
* the properties
|
||||
*/
|
||||
public ConfigInvocationHandler(Document properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
log.debug("Configuration service, method invoked: {}",
|
||||
method.getName());
|
||||
if (args == null || args.length == 0) {
|
||||
final ConfigurationPropertyGetter getter = method
|
||||
.getAnnotation(ConfigurationPropertyGetter.class);
|
||||
final ConfigurationXPath xpath = method
|
||||
.getAnnotation(ConfigurationXPath.class);
|
||||
if (getter == null)
|
||||
return null;
|
||||
if (xpath == null)
|
||||
return null;
|
||||
return get(getter, xpath, method.getReturnType());
|
||||
} else if (args.length == 1) {
|
||||
final ConfigurationXPath xpath = method
|
||||
.getAnnotation(ConfigurationXPath.class);
|
||||
if (xpath == null)
|
||||
return null;
|
||||
set(xpath, args[0], method.getParameterTypes()[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the untransformed value of an property
|
||||
*
|
||||
* @param getter
|
||||
* the getter annotation
|
||||
* @param xpath
|
||||
* the xpath annotation
|
||||
* @param type
|
||||
* the transformed type
|
||||
* @return the untransformed property
|
||||
*/
|
||||
private Object get(ConfigurationPropertyGetter getter,
|
||||
ConfigurationXPath xpath, Class<?> type) {
|
||||
if (cache.containsKey(xpath.value()))
|
||||
return cache.get(xpath.value());
|
||||
Object o;
|
||||
try {
|
||||
o = untransform(getRaw(xpath.value(), getter.defaultValue()),
|
||||
type);
|
||||
} catch (XPathExpressionException e) {
|
||||
return null;
|
||||
}
|
||||
cache.put(xpath.value(), o);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transformed value of an property
|
||||
*
|
||||
* @param xpath
|
||||
* the xpath annotation
|
||||
* @param value
|
||||
* the untransformed value
|
||||
* @param type
|
||||
* the transformed type
|
||||
* @throws XPathExpressionException
|
||||
* if any error occur while compiling the XPath
|
||||
*/
|
||||
private void set(ConfigurationXPath xpath, Object value, Class<?> type)
|
||||
throws XPathExpressionException {
|
||||
Node node = (Node) XPathFactory.newInstance().newXPath()
|
||||
.compile(xpath.value())
|
||||
.evaluate(properties, XPathConstants.NODE);
|
||||
if (value != null) {
|
||||
node.setNodeValue(transform(value.toString(), type));
|
||||
cache.put(xpath.value(), value);
|
||||
} else {
|
||||
node.getParentNode().removeChild(node);
|
||||
cache.remove(xpath.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Untransforms an value
|
||||
*
|
||||
* @param value
|
||||
* the raw value
|
||||
* @param type
|
||||
* the output type
|
||||
* @return the untransformed value
|
||||
*/
|
||||
private Object untransform(String value, Class<?> type) {
|
||||
if (value == null)
|
||||
return null;
|
||||
if (type == String.class)
|
||||
return value;
|
||||
final Transformer<?> transformer = TransformerFactory
|
||||
.getTransfromer(type);
|
||||
if (transformer == null)
|
||||
return null;
|
||||
return transformer.untransform(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an value
|
||||
*
|
||||
* @param value
|
||||
* the raw typed value
|
||||
* @param type
|
||||
* the input type
|
||||
* @return the string representing <tt>value</tt>
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private String transform(Object value, Class<?> type) {
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value instanceof String)
|
||||
return (String) value;
|
||||
final Transformer transformer = TransformerFactory
|
||||
.getTransfromer(type);
|
||||
if (transformer == null)
|
||||
return null;
|
||||
return transformer.transform(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw value from the property file
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param defaultValue
|
||||
* the default value
|
||||
* @return the value found or default value
|
||||
* @throws XPathExpressionException
|
||||
* if any XPath exception occur
|
||||
*/
|
||||
private String getRaw(String key, String defaultValue)
|
||||
throws XPathExpressionException {
|
||||
if (properties == null)
|
||||
return defaultValue;
|
||||
String value = XPathFactory.newInstance().newXPath()
|
||||
.evaluate(key, properties);
|
||||
if (value == null || value.length() == 0)
|
||||
return defaultValue;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find an annotation in the class or any parent-class.
|
||||
*
|
||||
* @param <T>
|
||||
* the annotation type
|
||||
* @param annotationClass
|
||||
* the annotation class
|
||||
* @param clazz
|
||||
* the class to look for annotations
|
||||
* @return the annotation found
|
||||
*/
|
||||
private <T extends Annotation> T findAnnotation(Class<T> annotationClass,
|
||||
Class<?> clazz) {
|
||||
Preconditions.checkNotNull(annotationClass, "annotationClass");
|
||||
Preconditions.checkNotNull(clazz, "clazz");
|
||||
|
||||
T ann = clazz.getAnnotation(annotationClass);
|
||||
if (ann != null)
|
||||
return ann;
|
||||
|
||||
for (Class<?> clazz2 : annotationClass.getInterfaces()) {
|
||||
if (clazz2 == clazz)
|
||||
continue;
|
||||
ann = findAnnotation(annotationClass, clazz2);
|
||||
if (ann != null)
|
||||
return ann;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configuration store directory
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core;
|
||||
|
||||
import com.l2jserver.service.Service;
|
||||
|
||||
/**
|
||||
* Service used to manage unhandled exceptions
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface ExceptionService extends Service {
|
||||
/**
|
||||
* Handles an unhandled exception
|
||||
*
|
||||
* @param t
|
||||
* the exception
|
||||
*/
|
||||
void thrown(Throwable t);
|
||||
|
||||
/**
|
||||
* Handles an unhandled exception and rethrows it again
|
||||
*
|
||||
* @param <T>
|
||||
* the exception type
|
||||
* @param t
|
||||
* the exception
|
||||
* @throws T
|
||||
* same exception in <tt>t</tt>
|
||||
*/
|
||||
<T extends Throwable> void rethrown(T t) throws T;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core;
|
||||
|
||||
import org.apache.log4j.BasicConfigurator;
|
||||
import org.apache.log4j.ConsoleAppender;
|
||||
import org.apache.log4j.Layout;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
|
||||
/**
|
||||
* Logging service implementation for Log4J
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class Log4JLoggingService extends AbstractService implements
|
||||
LoggingService {
|
||||
/**
|
||||
* The root logger
|
||||
*/
|
||||
private Logger rootLogger;
|
||||
/**
|
||||
* The l2j logger
|
||||
*/
|
||||
private Logger l2jLogger;
|
||||
/**
|
||||
* The netty logger
|
||||
*/
|
||||
private Logger nettyLogger;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
final Layout layout = new PatternLayout(
|
||||
"[%p %d{yyyy-MM-dd HH-mm-ss}] %c:%L - %m%n");
|
||||
|
||||
BasicConfigurator.configure();
|
||||
rootLogger = Logger.getRootLogger();
|
||||
l2jLogger = Logger.getLogger("com.l2jserver");
|
||||
nettyLogger = Logger.getLogger("org.jboss.netty");
|
||||
|
||||
rootLogger.removeAllAppenders();
|
||||
rootLogger.setLevel(Level.WARN);
|
||||
rootLogger.addAppender(new ConsoleAppender(layout, "System.err"));
|
||||
|
||||
l2jLogger.setLevel(Level.INFO);
|
||||
nettyLogger.setLevel(Level.DEBUG);
|
||||
Logger.getLogger("com.l2jserver.model.id.object.allocator").setLevel(
|
||||
Level.WARN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ServiceStopException {
|
||||
BasicConfigurator.resetConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core;
|
||||
|
||||
import com.l2jserver.service.Service;
|
||||
|
||||
/**
|
||||
* This service initializes and configures the logging provider. Currently SLF4J
|
||||
* is used and implementations must initialize SLF4J and its respective binding.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface LoggingService extends Service {
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.log4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.log4j.FileAppender;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
/**
|
||||
* This class is appender that zips old file instead of appending it.<br>
|
||||
* File is recognized as old if it's lastModified() is < JVM startup time.<br>
|
||||
* So we can have per-run appending. <br>
|
||||
*
|
||||
* Unfortunately, UNIX systems doesn't support file creation date, so we have to
|
||||
* use lastModified(), windows only solution is not good.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class TruncateToZipFileAppender extends FileAppender {
|
||||
/**
|
||||
* String that points to root directory for backups
|
||||
*/
|
||||
private String backupDir = "log/backup";
|
||||
|
||||
/**
|
||||
* String that represents date format for backup files
|
||||
*/
|
||||
private String backupDateFormat = "yyyy-MM-dd HH-mm-ss";
|
||||
|
||||
/**
|
||||
* Sets and <i>opens</i> the file where the log output will go. The
|
||||
* specified file must be writable.
|
||||
* <p>
|
||||
* If there was already an opened file, then the previous file is closed
|
||||
* first.
|
||||
* <p/>
|
||||
* <p>
|
||||
* <b>Do not use this method directly. To configure a FileAppender or one of
|
||||
* its subclasses, set its properties one by one and then call
|
||||
* activateOptions.</b>
|
||||
* <p/>
|
||||
* <br>
|
||||
* Truncation is done by {@link #truncate(java.io.File)}
|
||||
*
|
||||
* @param fileName
|
||||
* The path to the log file.
|
||||
* @param append
|
||||
* If true will append to fileName. Otherwise will truncate
|
||||
* fileName.
|
||||
*/
|
||||
@Override
|
||||
public void setFile(String fileName, boolean append, boolean bufferedIO,
|
||||
int bufferSize) throws IOException {
|
||||
|
||||
if (!append) {
|
||||
truncate(new File(fileName));
|
||||
}
|
||||
|
||||
super.setFile(fileName, append, bufferedIO, bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates archive with file instead of deleting it.
|
||||
*
|
||||
* @param file
|
||||
* file to truncate
|
||||
*/
|
||||
protected void truncate(File file) {
|
||||
LogLog.debug("Compression of file: " + file.getAbsolutePath()
|
||||
+ " started.");
|
||||
|
||||
// Linux systems doesn't provide file creation time, so we have to hope
|
||||
// that log files
|
||||
// were not modified manually after server starup
|
||||
// We can use here Windowns-only solution but that suck :(
|
||||
if (FileUtils.isFileOlder(file, ManagementFactory.getRuntimeMXBean()
|
||||
.getStartTime())) {
|
||||
File backupRoot = new File(getBackupDir());
|
||||
if (!backupRoot.exists() && !backupRoot.mkdirs()) {
|
||||
throw new Error("Can't create backup dir for backup storage");
|
||||
}
|
||||
|
||||
SimpleDateFormat df;
|
||||
try {
|
||||
df = new SimpleDateFormat(getBackupDateFormat());
|
||||
} catch (Exception e) {
|
||||
throw new Error("Invalid date formate for backup files: "
|
||||
+ getBackupDateFormat(), e);
|
||||
}
|
||||
String date = df.format(new Date(file.lastModified()));
|
||||
|
||||
File zipFile = new File(backupRoot, file.getName() + "." + date
|
||||
+ ".zip");
|
||||
|
||||
ZipOutputStream zos = null;
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
zos = new ZipOutputStream(new FileOutputStream(zipFile));
|
||||
ZipEntry entry = new ZipEntry(file.getName());
|
||||
entry.setMethod(ZipEntry.DEFLATED);
|
||||
entry.setCrc(FileUtils.checksumCRC32(file));
|
||||
zos.putNextEntry(entry);
|
||||
fis = FileUtils.openInputStream(file);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int readed;
|
||||
while ((readed = fis.read(buffer)) != -1) {
|
||||
zos.write(buffer, 0, readed);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new Error("Can't create zip file", e);
|
||||
} finally {
|
||||
if (zos != null) {
|
||||
try {
|
||||
zos.close();
|
||||
} catch (IOException e) {
|
||||
// not critical error
|
||||
LogLog.warn("Can't close zip file", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (fis != null) {
|
||||
try {
|
||||
// not critical error
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
LogLog.warn("Can't close zipped file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!file.delete()) {
|
||||
throw new Error("Can't delete old log file "
|
||||
+ file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns root directory for backups
|
||||
*
|
||||
* @return root directory for backups
|
||||
*/
|
||||
public String getBackupDir() {
|
||||
return backupDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets root directory for backups
|
||||
*
|
||||
* @param backupDir
|
||||
* new root directory for backups
|
||||
*/
|
||||
public void setBackupDir(String backupDir) {
|
||||
this.backupDir = backupDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns date format that should be used for backup files represented as
|
||||
* string
|
||||
*
|
||||
* @return date formate for backup files
|
||||
*/
|
||||
public String getBackupDateFormat() {
|
||||
return backupDateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets date format for bakcup files represented as string
|
||||
*
|
||||
* @param backupDateFormat
|
||||
* date format for backup files
|
||||
*/
|
||||
public void setBackupDateFormat(String backupDateFormat) {
|
||||
this.backupDateFormat = backupDateFormat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.threading;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* This future instance extends {@link Future} but also adds some additional
|
||||
* features, such as waiting for an given task to finish.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @param <T>
|
||||
* the {@link Future} return type
|
||||
*/
|
||||
public interface AsyncFuture<T> extends Future<T> {
|
||||
/**
|
||||
* Waits until the task is executed
|
||||
*
|
||||
* @throws ExecutionException
|
||||
* if the thread has been interrupted while waiting
|
||||
*/
|
||||
void await() throws ExecutionException;
|
||||
|
||||
/**
|
||||
* Waits until the task is executed
|
||||
*
|
||||
* @param timeout
|
||||
* the timeout
|
||||
* @param unit
|
||||
* the timeout unit
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* if the thread has been interrupted while waiting
|
||||
* @throws TimeoutException
|
||||
* if timeout was exceeded
|
||||
*/
|
||||
void await(long timeout, TimeUnit unit) throws InterruptedException,
|
||||
TimeoutException;
|
||||
|
||||
/**
|
||||
* Waits until the task is executed
|
||||
*
|
||||
* @return true if execution ended with no error, false otherwise
|
||||
*/
|
||||
boolean awaitUninterruptibly();
|
||||
|
||||
/**
|
||||
* Waits until the task is executed
|
||||
*
|
||||
* @param timeout
|
||||
* the timeout
|
||||
* @param unit
|
||||
* the timeout unit
|
||||
*
|
||||
* @return true if execution ended with no error, false otherwise. Please
|
||||
* note that false will be returned if the timeout has expired too!
|
||||
*/
|
||||
boolean awaitUninterruptibly(long timeout, TimeUnit unit);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.threading;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* This future instance extends {@link ScheduledFuture}. An scheduled future
|
||||
* cannot return values neither await for its termination because its execution
|
||||
* is continuously repeated.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface ScheduledAsyncFuture extends ScheduledFuture<Object> {
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.threading;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This is an ThreadPool you can use it to schedule tasks in the future or to
|
||||
* repeat them many times.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface ThreadPool {
|
||||
/**
|
||||
* Executes an asynchronous tasks.
|
||||
*
|
||||
* @param <T>
|
||||
* the task return type
|
||||
* @param callable
|
||||
* the callable instance
|
||||
* @return the {@link AsyncFuture} notified once the task has completed
|
||||
*/
|
||||
<T> AsyncFuture<T> async(Callable<T> callable);
|
||||
|
||||
/**
|
||||
* Executes an asynchronous tasks at an scheduled time.
|
||||
*
|
||||
* @param <T>
|
||||
* the task return type
|
||||
* @param callable
|
||||
* the callable instance
|
||||
* @param delay
|
||||
* the initial delay to wait before the task is executed
|
||||
* @param unit
|
||||
* the time unit of delay
|
||||
* @return the {@link AsyncFuture} notified once the task has completed
|
||||
*/
|
||||
<T> AsyncFuture<T> async(long delay, TimeUnit unit, Callable<T> callable);
|
||||
|
||||
/**
|
||||
* Executes an asynchronous tasks at an scheduled time.
|
||||
*
|
||||
* @param delay
|
||||
* the initial delay to wait before the task is executed
|
||||
* @param unit
|
||||
* the time unit of delay
|
||||
* @param repeat
|
||||
* the repeating interval for this task
|
||||
* @param task
|
||||
* the task to be executed
|
||||
* @return the {@link AsyncFuture} notified once the task has completed
|
||||
*/
|
||||
ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
|
||||
Runnable task);
|
||||
|
||||
/**
|
||||
* Disposes this thread pool. After disposing, it will no longer be able to
|
||||
* execute tasks.
|
||||
*/
|
||||
void dispose();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.threading;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.l2jserver.service.Service;
|
||||
|
||||
/**
|
||||
* This service is responsible for scheduling tasks and executing them in
|
||||
* parallel.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface ThreadService extends Service {
|
||||
/**
|
||||
* Executes an asynchronous tasks.
|
||||
* <p>
|
||||
* Tasks scheduled here will go to an default shared thread pool.
|
||||
*
|
||||
* @param <T>
|
||||
* the task return type
|
||||
* @param callable
|
||||
* the callable instance
|
||||
* @return the {@link AsyncFuture} notified once the task has completed
|
||||
*/
|
||||
<T> AsyncFuture<T> async(Callable<T> callable);
|
||||
|
||||
/**
|
||||
* Executes an asynchronous tasks at an scheduled time. <b>Please note that
|
||||
* resources in scheduled thread pool are limited and tasks should be
|
||||
* performed fast.</b>
|
||||
* <p>
|
||||
* Tasks scheduled here will go to an default shared thread pool.
|
||||
*
|
||||
* @param <T>
|
||||
* the task return type
|
||||
* @param callable
|
||||
* the callable instance
|
||||
* @param delay
|
||||
* the initial delay to wait before the task is executed
|
||||
* @param unit
|
||||
* the time unit of delay
|
||||
* @return the {@link AsyncFuture} notified once the task has completed
|
||||
*/
|
||||
<T> AsyncFuture<T> async(long delay, TimeUnit unit, Callable<T> callable);
|
||||
|
||||
/**
|
||||
* Executes an asynchronous tasks at an scheduled time. <b>Please note that
|
||||
* resources in scheduled thread pool are limited and tasks should be
|
||||
* performed fast.</b>
|
||||
* <p>
|
||||
* Tasks scheduled here will go to an default shared thread pool.
|
||||
*
|
||||
* @param delay
|
||||
* the initial delay to wait before the task is executed
|
||||
* @param unit
|
||||
* the time unit of delay
|
||||
* @param repeat
|
||||
* the repeating interval for this task
|
||||
* @param task
|
||||
* the task to be executed
|
||||
* @return the {@link AsyncFuture} notified once the task has completed
|
||||
*/
|
||||
ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
|
||||
Runnable task);
|
||||
|
||||
/**
|
||||
* Creates a new thread pool.
|
||||
*
|
||||
* @param name
|
||||
* the pool name
|
||||
* @param maxThreads
|
||||
* the maximum amount of threads.
|
||||
* @return the new thread pool
|
||||
*/
|
||||
ThreadPool createThreadPool(String name, int maxThreads);
|
||||
|
||||
/**
|
||||
* Disposes an given thread pool. After disposing the thread pool will no
|
||||
* longer be usable.
|
||||
*
|
||||
* @param pool
|
||||
* the thread pool to be disposed
|
||||
*/
|
||||
void dispose(ThreadPool pool);
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.threading;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
|
||||
/**
|
||||
* The default implementation for {@link ThreadService}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ThreadServiceImpl extends AbstractService implements ThreadService {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The public shared thread pool
|
||||
*/
|
||||
private ThreadPool pool;
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
pool = createThreadPool("shared", 20);
|
||||
// scheduler = Executors.newScheduledThreadPool(10);
|
||||
// async = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AsyncFuture<T> async(Callable<T> callable) {
|
||||
Preconditions.checkNotNull(callable, "callable");
|
||||
|
||||
log.debug("Scheduling async task: {}", callable);
|
||||
return pool.async(callable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AsyncFuture<T> async(long delay, TimeUnit unit,
|
||||
Callable<T> callable) {
|
||||
Preconditions.checkArgument(delay >= 0, "delay < 0");
|
||||
Preconditions.checkNotNull(unit, "unit");
|
||||
Preconditions.checkNotNull(callable, "callable");
|
||||
|
||||
log.debug("Scheduling async task in {}ms: {}", unit.toMillis(delay),
|
||||
callable);
|
||||
return pool.async(delay, unit, callable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
|
||||
Runnable task) {
|
||||
Preconditions.checkArgument(delay >= 0, "delay < 0");
|
||||
Preconditions.checkArgument(repeat >= 0, "repeat < 0");
|
||||
Preconditions.checkNotNull(unit, "unit");
|
||||
Preconditions.checkNotNull(task, "task");
|
||||
|
||||
log.debug("Scheduling repeating async task in {}ms each {}ms: {}",
|
||||
new Object[] { unit.toMillis(delay), unit.toMillis(repeat),
|
||||
task });
|
||||
return pool.async(delay, unit, repeat, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadPool createThreadPool(String name, int maxThreads) {
|
||||
log.debug("Creating new ThreadPool {} with maximum of {} threads",
|
||||
name, maxThreads);
|
||||
return new ThreadPoolImpl(name,
|
||||
Executors.newScheduledThreadPool(maxThreads));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(ThreadPool pool) {
|
||||
log.debug("Disposing ThreadPool {}", pool);
|
||||
if (pool instanceof ThreadPoolImpl)
|
||||
((ThreadPoolImpl) pool).executor.shutdown();
|
||||
throw new UnsupportedOperationException(
|
||||
"The given ThreadPool is not supported by this service");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ServiceStopException {
|
||||
dispose(pool);
|
||||
pool = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple delegated implementation for {@link AsyncFuture}
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @param <T>
|
||||
* the return type
|
||||
*/
|
||||
private class AsyncFutureImpl<T> implements AsyncFuture<T> {
|
||||
/**
|
||||
* The future that is delegated in this implementation
|
||||
*/
|
||||
private final Future<T> future;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param future
|
||||
* the future
|
||||
*/
|
||||
private AsyncFutureImpl(Future<T> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return future.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return future.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return future.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return future.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
return future.get(timeout, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void await() throws ExecutionException {
|
||||
try {
|
||||
this.get();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void await(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, TimeoutException {
|
||||
try {
|
||||
this.get(timeout, unit);
|
||||
} catch (ExecutionException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean awaitUninterruptibly() {
|
||||
try {
|
||||
this.get();
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
} catch (ExecutionException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
|
||||
try {
|
||||
this.get(timeout, unit);
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
} catch (ExecutionException e) {
|
||||
return false;
|
||||
} catch (TimeoutException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Future implementation for asynchronous tasks
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
private class ScheduledAsyncFutureImpl implements ScheduledAsyncFuture {
|
||||
/**
|
||||
* The {@link ExecutorService} {@link ScheduledFuture}
|
||||
*/
|
||||
private final ScheduledFuture<?> future;
|
||||
|
||||
/**
|
||||
* @param future
|
||||
* the {@link ExecutorService} {@link ScheduledFuture}
|
||||
*/
|
||||
public ScheduledAsyncFutureImpl(ScheduledFuture<?> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return future.getDelay(unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return future.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed o) {
|
||||
return future.compareTo(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return future.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return future.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread pool implementation
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
private class ThreadPoolImpl implements ThreadPool {
|
||||
/**
|
||||
* This thread pool name
|
||||
*/
|
||||
private final String name;
|
||||
/**
|
||||
* The backing executor
|
||||
*/
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the pool name
|
||||
* @param executor
|
||||
* the backing {@link ScheduledExecutorService}
|
||||
*/
|
||||
public ThreadPoolImpl(String name, ScheduledExecutorService executor) {
|
||||
this.name = name;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AsyncFuture<T> async(Callable<T> callable) {
|
||||
log.debug("Task {} submited to {}", callable, name);
|
||||
return new AsyncFutureImpl<T>(executor.submit(callable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AsyncFuture<T> async(long delay, TimeUnit unit,
|
||||
Callable<T> callable) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Task {} scheduled in {} {} to {}", new Object[] {
|
||||
callable, delay, unit, name });
|
||||
return new AsyncFutureImpl<T>(executor.schedule(callable, delay,
|
||||
unit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledAsyncFuture async(long delay, TimeUnit unit,
|
||||
long repeat, Runnable task) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Task {} scheduled every {} {} to {}", new Object[] {
|
||||
task, repeat, unit, name });
|
||||
return new ScheduledAsyncFutureImpl(executor.scheduleAtFixedRate(
|
||||
task, delay, repeat, unit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
ThreadServiceImpl.this.dispose(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.vfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.l2jserver.service.AbstractService;
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
import com.l2jserver.service.configuration.ConfigurationService;
|
||||
|
||||
/**
|
||||
* Implementation of {@link VFSService} using default Java7 APIs.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class Java7VFSService extends AbstractService implements VFSService {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* The Java 7 vfs configuration
|
||||
*/
|
||||
private final Java7VFSConfiguration config;
|
||||
|
||||
/**
|
||||
* The {@link FileSystem} implementation
|
||||
*/
|
||||
private FileSystem fs;
|
||||
/**
|
||||
* The root {@link Path} of the server data
|
||||
*/
|
||||
private Path root;
|
||||
|
||||
/**
|
||||
* Configuration interface for {@link Java7VFSService}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface Java7VFSConfiguration extends VFSConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param configService
|
||||
* the configuration service
|
||||
*/
|
||||
@Inject
|
||||
protected Java7VFSService(final ConfigurationService configService) {
|
||||
this.config = configService.get(Java7VFSConfiguration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
try {
|
||||
fs = FileSystems.getFileSystem(new URI("file:///"));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ServiceStartException(e);
|
||||
}
|
||||
root = config.getRoot().toAbsolutePath();
|
||||
log.debug("Root path is {}", root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path resolve(String path) {
|
||||
log.debug("Resolving file {}", path);
|
||||
return root.resolve(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ServiceStopException {
|
||||
try {
|
||||
fs.close();
|
||||
} catch (IOException e) {
|
||||
throw new ServiceStopException(e);
|
||||
} finally {
|
||||
fs = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.vfs;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.l2jserver.service.Service;
|
||||
import com.l2jserver.service.ServiceConfiguration;
|
||||
import com.l2jserver.service.configuration.Configuration;
|
||||
import com.l2jserver.service.configuration.ProxyConfigurationService.ConfigurationName;
|
||||
import com.l2jserver.service.configuration.ProxyConfigurationService.ConfigurationPropertiesKey;
|
||||
import com.l2jserver.service.configuration.XMLConfigurationService.ConfigurationXPath;
|
||||
|
||||
/**
|
||||
* The VFS service is responsible for creating a Virtual File System that is
|
||||
* capable of reading files inside ZIP, TAR, BZIP and GZIP.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface VFSService extends Service {
|
||||
/**
|
||||
* VFS service configuration
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @see Configuration
|
||||
*/
|
||||
@ConfigurationName("vfs")
|
||||
public interface VFSConfiguration extends ServiceConfiguration {
|
||||
/**
|
||||
* @return the VFS root {@link URI}
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "")
|
||||
@ConfigurationPropertiesKey("vfs.root")
|
||||
@ConfigurationXPath("/configuration/services/vfs/root")
|
||||
Path getRoot();
|
||||
|
||||
/**
|
||||
* @param root
|
||||
* the new VFS root {@link URI}
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("vfs.root")
|
||||
@ConfigurationXPath("/configuration/services/vfs/root")
|
||||
void setRoot(Path root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an file. If the file cannot be resolved, null will be returned.
|
||||
* <p>
|
||||
* Please note that event if the file DOES NOT exists a valid object will be
|
||||
* returned.
|
||||
*
|
||||
* @param path
|
||||
* the file path as an string
|
||||
* @return the resolved file. Will return null if could not resolve.
|
||||
*/
|
||||
Path resolve(String path);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.database;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.l2jserver.model.Model;
|
||||
import com.l2jserver.model.id.ID;
|
||||
|
||||
/**
|
||||
* Abstract DAO implementations. Store an instance of {@link DatabaseService}.
|
||||
* Default {@link Iterator} implementation in this class supports
|
||||
* {@link Iterator#remove()} and will delete the row from the database.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the dao object type
|
||||
* @param <I>
|
||||
* the object id type
|
||||
*/
|
||||
public abstract class AbstractDAO<T extends Model<?>, I extends ID<?>>
|
||||
implements DataAccessObject<T, I> {
|
||||
/**
|
||||
* The database service instance
|
||||
*/
|
||||
protected final DatabaseService database;
|
||||
|
||||
/**
|
||||
* @param database
|
||||
* the database service
|
||||
*/
|
||||
@Inject
|
||||
protected AbstractDAO(DatabaseService database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(T object) {
|
||||
return save(object, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(T object, boolean force) {
|
||||
switch (object.getObjectDesire()) {
|
||||
case INSERT:
|
||||
return insert(object);
|
||||
case UPDATE:
|
||||
return update(object);
|
||||
case DELETE:
|
||||
return delete(object);
|
||||
case NONE:
|
||||
return (force ? update(object) : false);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
/**
|
||||
* The Iterator that will return the ID objects
|
||||
*/
|
||||
private final Iterator<I> iterator = AbstractDAO.this.selectIDs()
|
||||
.iterator();
|
||||
/**
|
||||
* The last used ID (will be used to remove the last element)
|
||||
*/
|
||||
private I lastID;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
lastID = iterator.next();
|
||||
if (lastID == null)
|
||||
return null;
|
||||
return select(lastID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
AbstractDAO.this.delete(select(lastID));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the database service
|
||||
*/
|
||||
public DatabaseService getDatabase() {
|
||||
return database;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,820 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.database;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp.ConnectionFactory;
|
||||
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
|
||||
import org.apache.commons.dbcp.PoolableConnectionFactory;
|
||||
import org.apache.commons.dbcp.PoolingDataSource;
|
||||
import org.apache.commons.pool.impl.GenericObjectPool;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This is an implementation of {@link DatabaseService} that provides an layer
|
||||
* to JDBC.
|
||||
*
|
||||
* <h1>Internal specification</h1> <h2>The {@link Query} object</h2>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* <h2>The {@link Mapper} object</h2>
|
||||
*
|
||||
* 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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class AbstractJDBCDatabaseService extends AbstractService
|
||||
implements DatabaseService {
|
||||
/**
|
||||
* The configuration object
|
||||
*/
|
||||
private final JDBCDatabaseConfiguration config;
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory
|
||||
.getLogger(AbstractJDBCDatabaseService.class);
|
||||
|
||||
/**
|
||||
* The cache service
|
||||
*/
|
||||
private final CacheService cacheService;
|
||||
/**
|
||||
* The thread service
|
||||
*/
|
||||
private final ThreadService threadService;
|
||||
|
||||
/**
|
||||
* The database connection pool
|
||||
*/
|
||||
private GenericObjectPool connectionPool;
|
||||
/**
|
||||
* The dayabase connection factory
|
||||
*/
|
||||
private ConnectionFactory connectionFactory;
|
||||
/**
|
||||
* The poolable connection factory
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private PoolableConnectionFactory poolableConnectionFactory;
|
||||
/**
|
||||
* The connection {@link DataSource}.
|
||||
*/
|
||||
private PoolingDataSource dataSource;
|
||||
|
||||
/**
|
||||
* An cache object
|
||||
*/
|
||||
private Cache<Object, Model<?>> 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 AbstractJDBCDatabaseService}.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface JDBCDatabaseConfiguration extends DatabaseConfiguration {
|
||||
/**
|
||||
* @return the jdbc url
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "jdbc:mysql://localhost/l2jserver2")
|
||||
@ConfigurationPropertiesKey("jdbc.url")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/url")
|
||||
String getJdbcUrl();
|
||||
|
||||
/**
|
||||
* @param jdbcUrl
|
||||
* the new jdbc url
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.url")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/url")
|
||||
void setJdbcUrl(String jdbcUrl);
|
||||
|
||||
/**
|
||||
* @return the jdbc driver class
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "com.jdbc.jdbc.Driver")
|
||||
@ConfigurationPropertiesKey("jdbc.driver")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/driver")
|
||||
String getDriver();
|
||||
|
||||
/**
|
||||
* @param driver
|
||||
* the new jdbc driver
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.driver")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/driver")
|
||||
void setDriver(Class<?> driver);
|
||||
|
||||
/**
|
||||
* @return the jdbc database username
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "l2j")
|
||||
@ConfigurationPropertiesKey("jdbc.username")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/username")
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* @param username
|
||||
* the jdbc database username
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.username")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/username")
|
||||
void setUsername(String username);
|
||||
|
||||
/**
|
||||
* @return the jdbc database password
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "changeme")
|
||||
@ConfigurationPropertiesKey("jdbc.password")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/password")
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* the jdbc database password
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.password")
|
||||
@ConfigurationXPath("/configuration/services/database/jdbc/password")
|
||||
void setPassword(String password);
|
||||
|
||||
/**
|
||||
* @return the maximum number of active connections
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "20")
|
||||
@ConfigurationPropertiesKey("jdbc.active.max")
|
||||
@ConfigurationXPath("/configuration/services/database/connections/active-maximum")
|
||||
int getMaxActiveConnections();
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* the maximum number of active connections
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.active.max")
|
||||
@ConfigurationXPath("/configuration/services/database/connections/active-maximum")
|
||||
void setMaxActiveConnections(int password);
|
||||
|
||||
/**
|
||||
* @return the maximum number of idle connections
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "20")
|
||||
@ConfigurationPropertiesKey("jdbc.idle.max")
|
||||
@ConfigurationXPath("/configuration/services/database/connections/idle-maximum")
|
||||
int getMaxIdleConnections();
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* the maximum number of idle connections
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.idle.max")
|
||||
@ConfigurationXPath("/configuration/services/database/connections/idle-maximum")
|
||||
void setMaxIdleConnections(int password);
|
||||
|
||||
/**
|
||||
* @return the minimum number of idle connections
|
||||
*/
|
||||
@ConfigurationPropertyGetter(defaultValue = "5")
|
||||
@ConfigurationPropertiesKey("jdbc.idle.min")
|
||||
@ConfigurationXPath("/configuration/services/database/connections/idle-minimum")
|
||||
int getMinIdleConnections();
|
||||
|
||||
/**
|
||||
* @param password
|
||||
* the minimum number of idle connections
|
||||
*/
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationPropertiesKey("jdbc.idle.min")
|
||||
@ConfigurationXPath("/configuration/services/database/connections/idle-minimum")
|
||||
void setMinIdleConnections(int password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param configService
|
||||
* the configuration service
|
||||
* @param cacheService
|
||||
* the cache service
|
||||
* @param threadService
|
||||
* the thread service
|
||||
*/
|
||||
@Inject
|
||||
public AbstractJDBCDatabaseService(ConfigurationService configService,
|
||||
CacheService cacheService, ThreadService threadService) {
|
||||
config = configService.get(JDBCDatabaseConfiguration.class);
|
||||
this.cacheService = cacheService;
|
||||
this.threadService = threadService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ServiceStartException {
|
||||
connectionPool = new GenericObjectPool(null);
|
||||
connectionPool.setMaxActive(config.getMaxActiveConnections());
|
||||
connectionPool.setMinIdle(config.getMinIdleConnections());
|
||||
connectionPool.setMaxIdle(config.getMaxIdleConnections());
|
||||
|
||||
// test if connections are active while idle
|
||||
connectionPool.setTestWhileIdle(true);
|
||||
|
||||
connectionFactory = new DriverManagerConnectionFactory(
|
||||
config.getJdbcUrl(), config.getUsername(), config.getPassword());
|
||||
poolableConnectionFactory = new PoolableConnectionFactory(
|
||||
connectionFactory, connectionPool, null, "SELECT 1", false,
|
||||
true);
|
||||
dataSource = new PoolingDataSource(connectionPool);
|
||||
|
||||
// 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<Model<?>, ?> dao = getDAO(object
|
||||
.getClass());
|
||||
if (dao.save(object)) {
|
||||
objects++;
|
||||
}
|
||||
}
|
||||
log.info(
|
||||
"{} objects have been saved by the auto save task",
|
||||
objects);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an <tt>query</tt> in the database.
|
||||
*
|
||||
* @param <T>
|
||||
* the query return type
|
||||
* @param query
|
||||
* the query
|
||||
* @return an instance of <tt>T</tt>
|
||||
*/
|
||||
public <T> T query(Query<T> query) {
|
||||
Preconditions.checkNotNull(query, "query");
|
||||
try {
|
||||
final Connection conn = dataSource.getConnection();
|
||||
log.debug("Executing query {} with {}", query, conn);
|
||||
try {
|
||||
return query.query(conn);
|
||||
} catch (SQLException e) {
|
||||
log.error("Error executing query", e);
|
||||
return null;
|
||||
} finally {
|
||||
conn.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Could not open database connection", 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;
|
||||
|
||||
try {
|
||||
if (connectionPool != null)
|
||||
connectionPool.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Error stopping database service", e);
|
||||
throw new ServiceStopException(e);
|
||||
} finally {
|
||||
connectionPool = null;
|
||||
connectionFactory = null;
|
||||
poolableConnectionFactory = null;
|
||||
dataSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The query interface. The query will receive an connection an will be
|
||||
* executed. The can return return a value if required.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <R>
|
||||
* the return type
|
||||
*/
|
||||
public interface Query<R> {
|
||||
/**
|
||||
* Execute the query in <tt>conn</tt>
|
||||
*
|
||||
* @param conn
|
||||
* the connection
|
||||
* @return the query return value
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
R query(Connection conn) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* This query is used for the following statements:
|
||||
* <ul>
|
||||
* <li>INSERT INTO</li>
|
||||
* <li>UPDATE</li>
|
||||
* <li>DELETE FROM</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the query return type
|
||||
*/
|
||||
public static abstract class InsertUpdateQuery<T> implements Query<Integer> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory
|
||||
.getLogger(InsertUpdateQuery.class);
|
||||
|
||||
/**
|
||||
* The iterator
|
||||
*/
|
||||
private final Iterator<T> iterator;
|
||||
|
||||
/**
|
||||
* Creates a new query for <tt>objects</tt>
|
||||
*
|
||||
* @param objects
|
||||
* the object list
|
||||
*/
|
||||
public InsertUpdateQuery(T... objects) {
|
||||
this(new ArrayIterator<T>(objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new query for objects in <tt>iterator</tt>
|
||||
*
|
||||
* @param iterator
|
||||
* the object iterator
|
||||
*/
|
||||
public InsertUpdateQuery(Iterator<T> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Integer query(Connection conn) throws SQLException {
|
||||
Preconditions.checkNotNull(conn, "conn");
|
||||
|
||||
log.debug("Starting INSERT/UPDATE query execution");
|
||||
|
||||
int rows = 0;
|
||||
while (iterator.hasNext()) {
|
||||
final T object = iterator.next();
|
||||
final String queryString = query();
|
||||
|
||||
log.debug("Preparing statement for {}: {}", object, queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(queryString,
|
||||
Statement.RETURN_GENERATED_KEYS);
|
||||
|
||||
log.debug("Parametizing statement {} with {}", st, object);
|
||||
this.parametize(st, object);
|
||||
|
||||
log.debug("Sending query to database for {}", object);
|
||||
rows += st.executeUpdate();
|
||||
log.debug("Query inserted or updated {} rows for {}", rows,
|
||||
object);
|
||||
|
||||
// update object desire --it has been realized
|
||||
if (object instanceof Model && rows > 0) {
|
||||
log.debug("Updating Model ObjectDesire to NONE");
|
||||
((Model<?>) object).setObjectDesire(ObjectDesire.NONE);
|
||||
|
||||
final Mapper<? extends ID<?>> mapper = keyMapper();
|
||||
if (mapper == null)
|
||||
continue;
|
||||
final ResultSet rs = st.getGeneratedKeys();
|
||||
log.debug("Mapping generated keys with {} using {}",
|
||||
mapper, rs);
|
||||
while (rs.next()) {
|
||||
final ID<?> generatedID = mapper.map(rs);
|
||||
log.debug("Generated ID for {} is {}", object,
|
||||
generatedID);
|
||||
((Model<ID<?>>) object).setID(generatedID);
|
||||
mapper.map(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the <b>prepared</b> query for execution
|
||||
*
|
||||
* @return the <b>prepared</b> query
|
||||
*/
|
||||
protected abstract String query();
|
||||
|
||||
/**
|
||||
* Set the parameters for in <tt>statement</tt> for <tt>object</tt>
|
||||
*
|
||||
* @param st
|
||||
* the prepared statement
|
||||
* @param object
|
||||
* the object
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
protected abstract void parametize(PreparedStatement st, 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<? extends ID<?>> keyMapper() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An select query that returns a list of objects of type <tt>T</tt>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the query return type
|
||||
*/
|
||||
public static abstract class SelectListQuery<T> implements Query<List<T>> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory
|
||||
.getLogger(SelectListQuery.class);
|
||||
|
||||
@Override
|
||||
public List<T> query(Connection conn) throws SQLException {
|
||||
Preconditions.checkNotNull(conn, "conn");
|
||||
|
||||
log.debug("Starting SELECT List<?> query execution");
|
||||
|
||||
final String queryString = query();
|
||||
log.debug("Preparing statement with {}", queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(query());
|
||||
|
||||
log.debug("Parametizing statement {}", st);
|
||||
parametize(st);
|
||||
|
||||
log.debug("Sending query to database for {}", st);
|
||||
st.execute();
|
||||
|
||||
final List<T> list = CollectionFactory.newList();
|
||||
final ResultSet rs = st.getResultSet();
|
||||
final Mapper<T> mapper = mapper();
|
||||
log.debug("Database returned {}", rs);
|
||||
while (rs.next()) {
|
||||
log.debug("Mapping row with {}", mapper);
|
||||
final T obj = mapper.map(rs);
|
||||
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 <b>prepared</b> query for execution
|
||||
*
|
||||
* @return the <b>prepared</b> query
|
||||
*/
|
||||
protected abstract String query();
|
||||
|
||||
/**
|
||||
* Set the parameters for in <tt>statement</tt> for <tt>object</tt>
|
||||
*
|
||||
* @param st
|
||||
* the prepared statement
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
protected void parametize(PreparedStatement st) throws SQLException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapper that will bind {@link ResultSet} objects into an
|
||||
* <tt>T</tt> object instance. The mapper will need to create the object
|
||||
* instance.
|
||||
* <p>
|
||||
* <b>Note</b>: 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<T> mapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* An select query that returns a single object of type <tt>T</tt>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the query return type
|
||||
*/
|
||||
public static abstract class SelectSingleQuery<T> implements Query<T> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory
|
||||
.getLogger(SelectSingleQuery.class);
|
||||
|
||||
@Override
|
||||
public T query(Connection conn) throws SQLException {
|
||||
Preconditions.checkNotNull(conn, "conn");
|
||||
|
||||
log.debug("Starting SELECT single query execution");
|
||||
|
||||
final String queryString = query();
|
||||
log.debug("Preparing statement with {}", queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(query());
|
||||
|
||||
log.debug("Parametizing statement {}", st);
|
||||
parametize(st);
|
||||
|
||||
log.debug("Sending query to database for {}", st);
|
||||
st.execute();
|
||||
|
||||
final ResultSet rs = st.getResultSet();
|
||||
final Mapper<T> mapper = mapper();
|
||||
log.debug("Database returned {}", rs);
|
||||
while (rs.next()) {
|
||||
log.debug("Mapping row {} with {}", rs, mapper);
|
||||
final T object = mapper.map(rs);
|
||||
if (object instanceof Model)
|
||||
((Model<?>) object).setObjectDesire(ObjectDesire.NONE);
|
||||
log.debug("Mapper {} returned {}", mapper, object);
|
||||
return object;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the <b>prepared</b> query for execution
|
||||
*
|
||||
* @return the <b>prepared</b> query
|
||||
*/
|
||||
protected abstract String query();
|
||||
|
||||
/**
|
||||
* Set the parameters for in <tt>statement</tt> for <tt>object</tt>
|
||||
*
|
||||
* @param st
|
||||
* the prepared statement
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
protected void parametize(PreparedStatement st) throws SQLException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapper that will bind {@link ResultSet} objects into an
|
||||
* <tt>T</tt> object instance. The mapper will need to create the object
|
||||
* instance.
|
||||
*
|
||||
* @return the mapper
|
||||
*/
|
||||
protected abstract Mapper<T> mapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link Mapper} maps an {@link ResultSet} into an object <tt>T</tt>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the object type
|
||||
*/
|
||||
public interface Mapper<T> {
|
||||
/**
|
||||
* Map the result set value into an object.
|
||||
* <p>
|
||||
* <b>Note</b>: it is required to call {@link ResultSet#next()}, since
|
||||
* it is called by the {@link Query}.
|
||||
*
|
||||
* @param rs
|
||||
* the result set
|
||||
* @return the created instance
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
T map(ResultSet rs) 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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the object type
|
||||
* @param <I>
|
||||
* the id type
|
||||
*/
|
||||
public abstract static class CachedMapper<T extends Model<?>, I extends ID<?>>
|
||||
implements Mapper<T> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory
|
||||
.getLogger(SelectSingleQuery.class);
|
||||
|
||||
/**
|
||||
* The database service instance
|
||||
*/
|
||||
private final AbstractJDBCDatabaseService database;
|
||||
|
||||
/**
|
||||
* The {@link ID} mapper
|
||||
*/
|
||||
private final Mapper<I> idMapper;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param database
|
||||
* the database service
|
||||
* @param idMapper
|
||||
* the {@link ID} {@link Mapper}
|
||||
*/
|
||||
public CachedMapper(AbstractJDBCDatabaseService database,
|
||||
Mapper<I> idMapper) {
|
||||
this.database = database;
|
||||
this.idMapper = idMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final T map(ResultSet rs) throws SQLException {
|
||||
log.debug("Mapping row {} ID with {}", rs, idMapper);
|
||||
final I id = idMapper.map(rs);
|
||||
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, rs);
|
||||
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 rs
|
||||
* the jdbc result set
|
||||
* @return the created object
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
protected abstract T map(I id, ResultSet rs) throws SQLException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.database;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.l2jserver.model.Model;
|
||||
import com.l2jserver.model.id.ID;
|
||||
import com.l2jserver.service.cache.IgnoreCaching;
|
||||
|
||||
/**
|
||||
* The Data Access Object interface used used to retrieve, save and remove
|
||||
* objects from the database. The underlying storage engine can be an plain text
|
||||
* file, SQL Database or an serialized version of the object. This layer will
|
||||
* abstract the translation of the data and ease the transition from one engine
|
||||
* to another.
|
||||
* <p>
|
||||
* Every DAO is also an {@link Iterable}. If you wish you can iterate through
|
||||
* all objects in the database very abstractly. But please note that the default
|
||||
* {@link Iterator} implementation in {@link AbstractDAO} will load all the
|
||||
* {@link ID} objects and for every call {@link Iterator#next()}, a new database
|
||||
* query will be made requesting the given object. In a large dataset, this
|
||||
* could be a huge performance issue. DAO implementations are encouraged to
|
||||
* override the iterator implementation with a more specific implementation.
|
||||
*
|
||||
* @param <O>
|
||||
* the {@link Model} supported by this DAO
|
||||
* @param <I>
|
||||
* the ID used to represent the {@link Model} in this DAO
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
Iterable<O> {
|
||||
/**
|
||||
* Load the instance represented by <tt>id</tt> from the database
|
||||
*
|
||||
* @param id
|
||||
* the id
|
||||
* @return the selected object. <tt>null</tt> if could not be found in the
|
||||
* database.
|
||||
*/
|
||||
O select(I id);
|
||||
|
||||
/**
|
||||
* Loads an List of all {@link ID}s in the database
|
||||
*
|
||||
* @return the list containing all {@link ID} objects
|
||||
*/
|
||||
@IgnoreCaching
|
||||
Collection<I> selectIDs();
|
||||
|
||||
/**
|
||||
* Save the instance to the database. If a new database entry was created
|
||||
* returns true. This method will only save if the object has changed.
|
||||
*
|
||||
* @param object
|
||||
* the object
|
||||
* @return true if the row was inserted or updated
|
||||
* @see DataAccessObject#save(Model, boolean)
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean save(O object);
|
||||
|
||||
/**
|
||||
* Save the instance to the database. If a new database entry was created
|
||||
* returns true.
|
||||
*
|
||||
* @param object
|
||||
* the object
|
||||
* @param force
|
||||
* will force an save, even if the object has not changed
|
||||
* @return true if the row was inserted or updated
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean save(O object, boolean force);
|
||||
|
||||
/**
|
||||
* Inserts the instance in the database.
|
||||
*
|
||||
* @param object
|
||||
* the object
|
||||
* @return true if the row was inserted
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean insert(O object);
|
||||
|
||||
/**
|
||||
* Updates the instance in the database.
|
||||
*
|
||||
* @param object
|
||||
* the object
|
||||
* @return true if the row was updated
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean update(O object);
|
||||
|
||||
/**
|
||||
* Deletes the instance in the database.
|
||||
*
|
||||
* @param object
|
||||
* the object
|
||||
* @return true if the row was deleted
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean delete(O object);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
import com.l2jserver.service.configuration.ProxyConfigurationService.ConfigurationName;
|
||||
|
||||
/**
|
||||
* This service provides access to an database implementation. Each
|
||||
* implementation had its own {@link DataAccessObject} model, however they do
|
||||
* need to respect {@link DataAccessObject} interfaces located in "
|
||||
* <tt>com.l2jserver.db.dao</tt>". There can be several service implementation,
|
||||
* but only one of them can be active at an given time.
|
||||
*
|
||||
* The service does not directly provide much functionality most of its
|
||||
* operations are done trough an {@link DataAccessObject}. Each service
|
||||
* implementation provides an custom interface that is used to link
|
||||
* {@link DataAccessObject}-{@link DatabaseService Service}. See implementation
|
||||
* specific documentation for more information.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface DatabaseService extends Service {
|
||||
/**
|
||||
* Database service configuration
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
* @see Configuration
|
||||
*/
|
||||
@ConfigurationName("database")
|
||||
public interface DatabaseConfiguration extends ServiceConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DataAccessObject} used to retrieve and save objects of
|
||||
* type <M>
|
||||
*
|
||||
* @param <M>
|
||||
* the {@link Model} type
|
||||
* @param <I>
|
||||
* the {@link ID} type
|
||||
* @param model
|
||||
* the model class
|
||||
* @return the {@link DataAccessObject} for {@link Model}
|
||||
*/
|
||||
<M extends Model<I>, I extends ID<M>> DataAccessObject<M, I> getDAO(
|
||||
Class<M> model);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.database.jdbc;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.l2jserver.model.Model;
|
||||
import com.l2jserver.model.id.ID;
|
||||
import com.l2jserver.service.database.AbstractDAO;
|
||||
import com.l2jserver.service.database.DatabaseService;
|
||||
import com.l2jserver.service.database.AbstractJDBCDatabaseService;
|
||||
|
||||
/**
|
||||
* {@link AbstractDAO} for JDBC DAO implementation
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the object for the DAO
|
||||
* @param <I>
|
||||
* the object ID type
|
||||
*/
|
||||
public abstract class AbstractJDBCDAO<T extends Model<?>, I extends ID<?>>
|
||||
extends AbstractDAO<T, I> {
|
||||
/**
|
||||
* The JDBC Database Service
|
||||
*/
|
||||
protected final AbstractJDBCDatabaseService database;
|
||||
|
||||
/**
|
||||
* @param database
|
||||
* the database service
|
||||
*/
|
||||
@Inject
|
||||
protected AbstractJDBCDAO(DatabaseService database) {
|
||||
super(database);
|
||||
this.database = (AbstractJDBCDatabaseService) database;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* This {@link Iterator} takes an array as input and iterate over it.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the array type
|
||||
*/
|
||||
public class ArrayIterator<T> implements Iterator<T> {
|
||||
/**
|
||||
* The objects
|
||||
*/
|
||||
private final T[] objects;
|
||||
/**
|
||||
* the iterator index
|
||||
*/
|
||||
private int i = 0;
|
||||
|
||||
/**
|
||||
* Creates a new iterator instance
|
||||
*
|
||||
* @param objects
|
||||
* the objects
|
||||
*/
|
||||
public ArrayIterator(T... objects) {
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i < objects.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
try {
|
||||
return objects[i++];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
|
||||
/**
|
||||
* This is an Netty {@link ChannelBuffer} utility class.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class BufferUtils {
|
||||
/**
|
||||
* Reads an unicode string from the buffer
|
||||
*
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @return the read unicode string
|
||||
*/
|
||||
public static final String readString(ChannelBuffer buffer) {
|
||||
char[] str = new char[buffer.readableBytes()];
|
||||
int index = 0;
|
||||
char c;
|
||||
while ((c = buffer.readChar()) != 0) {
|
||||
str[index++] = c;
|
||||
}
|
||||
return String.valueOf(Arrays.copyOfRange(str, 0, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an unicode string to the buffer
|
||||
*
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @param str
|
||||
* the string
|
||||
*/
|
||||
public static final void writeString(ChannelBuffer buffer, String str) {
|
||||
if (str != null && str.length() > 0) {
|
||||
final int len = str.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
buffer.writeChar(str.charAt(i));
|
||||
}
|
||||
}
|
||||
buffer.writeShort(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
/**
|
||||
* This class contains utilities that are used when we are working with classes
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ClassUtils {
|
||||
/**
|
||||
* Return true if class a is either equivalent to class b, or if class a is
|
||||
* a subclass of class b, i.e. if a either "extends" or "implements" b. Note
|
||||
* that either or both "Class" objects may represent interfaces.
|
||||
*
|
||||
* @param a
|
||||
* class
|
||||
* @param b
|
||||
* class
|
||||
* @return true if a == b or a extends b or a implements b
|
||||
*/
|
||||
public static boolean isSubclass(Class<?> a, Class<?> b) {
|
||||
// We rely on the fact that for any given java class or
|
||||
// primitive type there is a unique Class object, so
|
||||
// we can use object equivalence in the comparisons.
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
for (Class<?> x = a; x != null; x = x.getSuperclass()) {
|
||||
if (x == b) {
|
||||
return true;
|
||||
}
|
||||
if (b.isInterface()) {
|
||||
Class<?> interfaces[] = x.getInterfaces();
|
||||
for (Class<?> anInterface : interfaces) {
|
||||
if (isSubclass(anInterface, b)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if class in member of the package
|
||||
*
|
||||
* @param clazz
|
||||
* class to check
|
||||
* @param packageName
|
||||
* package
|
||||
* @return true if is member
|
||||
*/
|
||||
public static boolean isPackageMember(Class<?> clazz, String packageName) {
|
||||
return isPackageMember(clazz.getName(), packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if classNames belongs to package
|
||||
*
|
||||
* @param className
|
||||
* class name
|
||||
* @param packageName
|
||||
* package
|
||||
* @return true if belongs
|
||||
*/
|
||||
public static boolean isPackageMember(String className, String packageName) {
|
||||
if (!className.contains(".")) {
|
||||
return packageName == null || packageName.isEmpty();
|
||||
} else {
|
||||
String classPackage = className.substring(0,
|
||||
className.lastIndexOf('.'));
|
||||
return packageName.equals(classPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
211
l2jserver2-common/src/main/java/com/l2jserver/util/MathUtil.java
Normal file
211
l2jserver2-common/src/main/java/com/l2jserver/util/MathUtil.java
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
import com.l2jserver.util.geometry.Point;
|
||||
import com.l2jserver.util.geometry.Point3D;
|
||||
|
||||
/**
|
||||
* Class with basic math.<br>
|
||||
* Thanks to:
|
||||
* <ul>
|
||||
* <li>http://geom-java.sourceforge.net/</li>
|
||||
* <li>
|
||||
* http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/DistancePoint.java</li>
|
||||
* </ul>
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class MathUtil {
|
||||
/**
|
||||
* Returns distance between two 2D points
|
||||
*
|
||||
* @param point1
|
||||
* first point
|
||||
* @param point2
|
||||
* second point
|
||||
* @return distance between points
|
||||
*/
|
||||
public static double getDistance(Point point1, Point point2) {
|
||||
return getDistance(point1.x, point1.y, point2.x, point2.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distance between two sets of coords
|
||||
*
|
||||
* @param x1
|
||||
* first x coord
|
||||
* @param y1
|
||||
* first y coord
|
||||
* @param x2
|
||||
* second x coord
|
||||
* @param y2
|
||||
* second y coord
|
||||
* @return distance between sets of coords
|
||||
*/
|
||||
public static double getDistance(int x1, int y1, int x2, int y2) {
|
||||
// using long to avoid possible overflows when multiplying
|
||||
long dx = x2 - x1;
|
||||
long dy = y2 - y1;
|
||||
|
||||
// return Math.hypot(x2 - x1, y2 - y1); // Extremely slow
|
||||
// return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); // 20 times faster
|
||||
// than hypot
|
||||
return Math.sqrt(dx * dx + dy * dy); // 10 times faster then previous
|
||||
// line
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distance between two 3D points
|
||||
*
|
||||
* @param point1
|
||||
* first point
|
||||
* @param point2
|
||||
* second point
|
||||
* @return distance between points
|
||||
*/
|
||||
public static double getDistance(Point3D point1, Point3D point2) {
|
||||
return getDistance(point1.getX(), point1.getY(), point1.getZ(),
|
||||
point2.getX(), point2.getY(), point2.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distance between 3D set of coords
|
||||
*
|
||||
* @param x1
|
||||
* first x coord
|
||||
* @param y1
|
||||
* first y coord
|
||||
* @param z1
|
||||
* first z coord
|
||||
* @param x2
|
||||
* second x coord
|
||||
* @param y2
|
||||
* second y coord
|
||||
* @param z2
|
||||
* second z coord
|
||||
* @return distance between coords
|
||||
*/
|
||||
public static double getDistance(float x1, float y1, float z1, float x2,
|
||||
float y2, float z2) {
|
||||
float dx = x1 - x2;
|
||||
float dy = y1 - y2;
|
||||
float dz = z1 - z2;
|
||||
|
||||
// We should avoid Math.pow or Math.hypot due to performance reasons
|
||||
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns closest point on segment to point
|
||||
*
|
||||
* @param ss
|
||||
* segment start point
|
||||
* @param se
|
||||
* segment end point
|
||||
* @param p
|
||||
* point to found closest point on segment
|
||||
* @return closest point on segment to p
|
||||
*/
|
||||
public static Point getClosestPointOnSegment(Point ss, Point se, Point p) {
|
||||
return getClosestPointOnSegment(ss.x, ss.y, se.x, se.y, p.x, p.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns closest point on segment to point
|
||||
*
|
||||
* @param sx1
|
||||
* segment x coord 1
|
||||
* @param sy1
|
||||
* segment y coord 1
|
||||
* @param sx2
|
||||
* segment x coord 2
|
||||
* @param sy2
|
||||
* segment y coord 2
|
||||
* @param px
|
||||
* point x coord
|
||||
* @param py
|
||||
* point y coord
|
||||
* @return closets point on segment to point
|
||||
*/
|
||||
public static Point getClosestPointOnSegment(int sx1, int sy1, int sx2,
|
||||
int sy2, int px, int py) {
|
||||
double xDelta = sx2 - sx1;
|
||||
double yDelta = sy2 - sy1;
|
||||
|
||||
if ((xDelta == 0) && (yDelta == 0)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Segment start equals segment end");
|
||||
}
|
||||
|
||||
double u = ((px - sx1) * xDelta + (py - sy1) * yDelta)
|
||||
/ (xDelta * xDelta + yDelta * yDelta);
|
||||
|
||||
final Point closestPoint;
|
||||
if (u < 0) {
|
||||
closestPoint = new Point(sx1, sy1);
|
||||
} else if (u > 1) {
|
||||
closestPoint = new Point(sx2, sy2);
|
||||
} else {
|
||||
closestPoint = new Point((int) Math.round(sx1 + u * xDelta),
|
||||
(int) Math.round(sy1 + u * yDelta));
|
||||
}
|
||||
|
||||
return closestPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distance to segment
|
||||
*
|
||||
* @param ss
|
||||
* segment start point
|
||||
* @param se
|
||||
* segment end point
|
||||
* @param p
|
||||
* point to found closest point on segment
|
||||
* @return distance to segment
|
||||
*/
|
||||
public static double getDistanceToSegment(Point ss, Point se, Point p) {
|
||||
return getDistanceToSegment(ss.x, ss.y, se.x, se.y, p.x, p.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns distance to segment
|
||||
*
|
||||
* @param sx1
|
||||
* segment x coord 1
|
||||
* @param sy1
|
||||
* segment y coord 1
|
||||
* @param sx2
|
||||
* segment x coord 2
|
||||
* @param sy2
|
||||
* segment y coord 2
|
||||
* @param px
|
||||
* point x coord
|
||||
* @param py
|
||||
* point y coord
|
||||
* @return distance to segment
|
||||
*/
|
||||
public static double getDistanceToSegment(int sx1, int sy1, int sx2,
|
||||
int sy2, int px, int py) {
|
||||
Point closestPoint = getClosestPointOnSegment(sx1, sy1, sx2, sy2, px,
|
||||
py);
|
||||
return getDistance(closestPoint.x, closestPoint.y, px, py);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 1999 CERN - European Organization for Nuclear Research.
|
||||
|
||||
// Permission to use, copy, modify, distribute and sell this software
|
||||
// and its documentation for any purpose is hereby granted without fee,
|
||||
// provided that the above copyright notice appear in all copies and
|
||||
// that both that copyright notice and this permission notice appear in
|
||||
// supporting documentation. CERN makes no representations about the
|
||||
// suitability of this software for any purpose. It is provided "as is"
|
||||
// without expressed or implied warranty.
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Used to keep hash table capacities prime numbers. Not of interest for users;
|
||||
* only for implementors of hashtables.
|
||||
*
|
||||
* <p>
|
||||
* Choosing prime numbers as hash table capacities is a good idea to keep them
|
||||
* working fast, particularly under hash table expansions.
|
||||
*
|
||||
* <p>
|
||||
* However, JDK 1.2, JGL 3.1 and many other toolkits do nothing to keep
|
||||
* capacities prime. This class provides efficient means to choose prime
|
||||
* capacities.
|
||||
*
|
||||
* <p>
|
||||
* Choosing a prime is <tt>O(log 300)</tt> (binary search in a list of 300
|
||||
* ints). Memory requirements: 1 KB static memory.
|
||||
*
|
||||
* @author wolfgang.hoschek@cern.ch
|
||||
* @version 1.0, 09/24/99
|
||||
*/
|
||||
public final class PrimeFinder {
|
||||
/**
|
||||
* The largest prime this class can generate; currently equal to
|
||||
* <tt>Integer.MAX_VALUE</tt>.
|
||||
*/
|
||||
public static final int LARGEST_PRIME = Integer.MAX_VALUE; // yes, it is
|
||||
// prime.
|
||||
|
||||
/**
|
||||
* The prime number list consists of 11 chunks.
|
||||
*
|
||||
* Each chunk contains prime numbers.
|
||||
*
|
||||
* A chunk starts with a prime P1. The next element is a prime P2. P2 is the
|
||||
* smallest prime for which holds: P2 >= 2*P1.
|
||||
*
|
||||
* The next element is P3, for which the same holds with respect to P2, and
|
||||
* so on.
|
||||
*
|
||||
* Chunks are chosen such that for any desired capacity >= 1000 the list
|
||||
* includes a prime number <= desired capacity * 1.11.
|
||||
*
|
||||
* Therefore, primes can be retrieved which are quite close to any desired
|
||||
* capacity, which in turn avoids wasting memory.
|
||||
*
|
||||
* For example, the list includes
|
||||
* 1039,1117,1201,1277,1361,1439,1523,1597,1759,1907,2081.
|
||||
*
|
||||
* So if you need a prime >= 1040, you will find a prime <= 1040*1.11=1154.
|
||||
*
|
||||
* Chunks are chosen such that they are optimized for a hashtable
|
||||
* growthfactor of 2.0;
|
||||
*
|
||||
* If your hashtable has such a growthfactor then, after initially
|
||||
* "rounding to a prime" upon hashtable construction, it will later expand
|
||||
* to prime capacities such that there exist no better primes.
|
||||
*
|
||||
* In total these are about 32*10=320 numbers -> 1 KB of static memory
|
||||
* needed.
|
||||
*
|
||||
* If you are stingy, then delete every second or fourth chunk.
|
||||
*/
|
||||
|
||||
private static final int[] PRIME_CAPACITIES = {
|
||||
// chunk #0
|
||||
LARGEST_PRIME,
|
||||
|
||||
// chunk #1
|
||||
5, 11, 23, 47, 97, 197,
|
||||
397,
|
||||
797,
|
||||
1597,
|
||||
3203,
|
||||
6421,
|
||||
12853,
|
||||
25717,
|
||||
51437,
|
||||
102877,
|
||||
205759,
|
||||
411527,
|
||||
823117,
|
||||
1646237,
|
||||
3292489,
|
||||
6584983,
|
||||
13169977,
|
||||
26339969,
|
||||
52679969,
|
||||
105359939,
|
||||
210719881,
|
||||
421439783,
|
||||
842879579,
|
||||
1685759167,
|
||||
|
||||
// chunk #2
|
||||
433, 877, 1759,
|
||||
3527,
|
||||
7057,
|
||||
14143,
|
||||
28289,
|
||||
56591,
|
||||
113189,
|
||||
226379,
|
||||
452759,
|
||||
905551,
|
||||
1811107,
|
||||
3622219,
|
||||
7244441,
|
||||
14488931,
|
||||
28977863,
|
||||
57955739,
|
||||
115911563,
|
||||
231823147,
|
||||
463646329,
|
||||
927292699,
|
||||
1854585413,
|
||||
|
||||
// chunk #3
|
||||
953, 1907, 3821, 7643,
|
||||
15287,
|
||||
30577,
|
||||
61169,
|
||||
122347,
|
||||
244703,
|
||||
489407,
|
||||
978821,
|
||||
1957651,
|
||||
3915341,
|
||||
7830701,
|
||||
15661423,
|
||||
31322867,
|
||||
62645741,
|
||||
125291483,
|
||||
250582987,
|
||||
501165979,
|
||||
1002331963,
|
||||
2004663929,
|
||||
|
||||
// chunk #4
|
||||
1039, 2081, 4177, 8363, 16729,
|
||||
33461,
|
||||
66923,
|
||||
133853,
|
||||
267713,
|
||||
535481,
|
||||
1070981,
|
||||
2141977,
|
||||
4283963,
|
||||
8567929,
|
||||
17135863,
|
||||
34271747,
|
||||
68543509,
|
||||
137087021,
|
||||
274174111,
|
||||
548348231,
|
||||
1096696463,
|
||||
|
||||
// chunk #5
|
||||
31, 67, 137, 277, 557, 1117, 2237, 4481, 8963, 17929, 35863, 71741,
|
||||
143483,
|
||||
286973,
|
||||
573953,
|
||||
1147921,
|
||||
2295859,
|
||||
4591721,
|
||||
9183457,
|
||||
18366923,
|
||||
36733847,
|
||||
73467739,
|
||||
146935499,
|
||||
293871013,
|
||||
587742049,
|
||||
1175484103,
|
||||
|
||||
// chunk #6
|
||||
599, 1201, 2411, 4831, 9677, 19373, 38747, 77509, 155027, 310081,
|
||||
620171, 1240361,
|
||||
2480729,
|
||||
4961459,
|
||||
9922933,
|
||||
19845871,
|
||||
39691759,
|
||||
79383533,
|
||||
158767069,
|
||||
317534141,
|
||||
635068283,
|
||||
1270136683,
|
||||
|
||||
// chunk #7
|
||||
311, 631, 1277, 2557, 5119, 10243, 20507, 41017, 82037, 164089,
|
||||
328213, 656429, 1312867, 2625761, 5251529,
|
||||
10503061,
|
||||
21006137,
|
||||
42012281,
|
||||
84024581,
|
||||
168049163,
|
||||
336098327,
|
||||
672196673,
|
||||
1344393353,
|
||||
|
||||
// chunk #8
|
||||
3, 7, 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911,
|
||||
43853, 87719, 175447, 350899, 701819, 1403641, 2807303, 5614657,
|
||||
11229331, 22458671, 44917381,
|
||||
89834777,
|
||||
179669557,
|
||||
359339171,
|
||||
718678369,
|
||||
1437356741,
|
||||
|
||||
// chunk #9
|
||||
43, 89, 179, 359, 719, 1439, 2879, 5779, 11579, 23159, 46327,
|
||||
92657, 185323, 370661, 741337, 1482707, 2965421, 5930887, 11861791,
|
||||
23723597, 47447201, 94894427, 189788857, 379577741,
|
||||
759155483,
|
||||
1518310967,
|
||||
|
||||
// chunk #10
|
||||
379, 761, 1523, 3049, 6101, 12203, 24407, 48817, 97649, 195311,
|
||||
390647, 781301, 1562611, 3125257, 6250537, 12501169, 25002389,
|
||||
50004791, 100009607, 200019221, 400038451, 800076929, 1600153859 };
|
||||
|
||||
static { // initializer
|
||||
// The above prime numbers are formatted for human readability.
|
||||
// To find numbers fast, we sort them once and for all.
|
||||
|
||||
Arrays.sort(PRIME_CAPACITIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prime number which is <code>>= desiredCapacity</code> and
|
||||
* very close to <code>desiredCapacity</code> (within 11% if
|
||||
* <code>desiredCapacity >= 1000</code>).
|
||||
*
|
||||
* @param desiredCapacity
|
||||
* the capacity desired by the user.
|
||||
* @return the capacity which should be used for a hashtable.
|
||||
*/
|
||||
public static final int nextPrime(int desiredCapacity) {
|
||||
int i = Arrays.binarySearch(PRIME_CAPACITIES, desiredCapacity);
|
||||
if (i < 0) {
|
||||
// desired capacity not found, choose next prime greater
|
||||
// than desired capacity
|
||||
i = -i - 1; // remember the semantics of binarySearch...
|
||||
}
|
||||
return PRIME_CAPACITIES[i];
|
||||
}
|
||||
}
|
||||
113
l2jserver2-common/src/main/java/com/l2jserver/util/RGBColor.java
Normal file
113
l2jserver2-common/src/main/java/com/l2jserver/util/RGBColor.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
/**
|
||||
* An RED-GREEN-BLUE color
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class RGBColor {
|
||||
/**
|
||||
* The red value
|
||||
*/
|
||||
private final byte red;
|
||||
/**
|
||||
* The green value
|
||||
*/
|
||||
private final byte green;
|
||||
/**
|
||||
* The blue value
|
||||
*/
|
||||
private final byte blue;
|
||||
|
||||
/**
|
||||
* Creates a new RGB (red-green-blue) color
|
||||
*
|
||||
* @param r
|
||||
* the red byte
|
||||
* @param g
|
||||
* the green byte
|
||||
* @param b
|
||||
* the blue byte
|
||||
*/
|
||||
protected RGBColor(byte r, byte g, byte b) {
|
||||
this.red = r;
|
||||
this.green = g;
|
||||
this.blue = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the red
|
||||
*/
|
||||
public byte getRed() {
|
||||
return red;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the green
|
||||
*/
|
||||
public byte getGreen() {
|
||||
return green;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the blue
|
||||
*/
|
||||
public byte getBlue() {
|
||||
return blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to an byte array
|
||||
*
|
||||
* @return an byte array of this color
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
return new byte[] { red, green, blue };
|
||||
}
|
||||
|
||||
/**
|
||||
* Convers this color into an integer
|
||||
*
|
||||
* @return the color integer
|
||||
*/
|
||||
public int toInteger() {
|
||||
return (red >> 24) + (green >> 16) + (blue >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link RGBColor} from an byte array
|
||||
*
|
||||
* @param rgb
|
||||
* the RGB byte array
|
||||
* @return the {@link RGBColor}
|
||||
*/
|
||||
public static RGBColor fromByteArray(byte[] rgb) {
|
||||
return new RGBColor(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param color
|
||||
* the color integer
|
||||
* @return the {@link RGBColor}
|
||||
*/
|
||||
public static RGBColor fromInteger(int color) {
|
||||
return new RGBColor((byte) (color << 0), (byte) (color << 8),
|
||||
(byte) (color << 16));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.exception;
|
||||
|
||||
/**
|
||||
* Base exception for Lineage 2
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class L2Exception extends Exception {
|
||||
/**
|
||||
* Default Serial Version UID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @see Exception#Exception()
|
||||
*/
|
||||
public L2Exception() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Exception#Exception(String, Throwable)
|
||||
*/
|
||||
public L2Exception(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Exception#Exception(String)
|
||||
*/
|
||||
public L2Exception(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Exception#Exception(Throwable)
|
||||
*/
|
||||
public L2Exception(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Each {@link L2Exception} has an {@link SystemMessage} attacked to it.
|
||||
// It
|
||||
// * is an <b><u>recommendation</u></b> of which message should be sent to
|
||||
// the
|
||||
// * client in case the exception is thrown.
|
||||
// *
|
||||
// * @return the recommended system message
|
||||
// */
|
||||
// public abstract SystemMessage getSystemMessage();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.factory;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import javolution.util.FastList;
|
||||
import javolution.util.FastMap;
|
||||
import javolution.util.FastSet;
|
||||
|
||||
/**
|
||||
* Factory class to create {@link Collection} instances.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class CollectionFactory {
|
||||
/**
|
||||
* Creates a new list of type <tt>T</tt>
|
||||
*
|
||||
* @param <T>
|
||||
* the type
|
||||
* @return the created list
|
||||
*/
|
||||
public static final <T> List<T> newList() {
|
||||
return new FastList<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set of type <tt>T</tt>
|
||||
*
|
||||
* @param <T>
|
||||
* the type
|
||||
* @return the created set
|
||||
*/
|
||||
public static final <T> Set<T> newSet() {
|
||||
return new FastSet<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new concurrent queue of type <tt>T</tt>
|
||||
*
|
||||
* @param <T>
|
||||
* the type
|
||||
* @return the created queue
|
||||
*/
|
||||
public static final <T> Queue<T> newConcurrentQueue() {
|
||||
return new ConcurrentLinkedQueue<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new priority queue of type <tt>T</tt>
|
||||
*
|
||||
* @param <T>
|
||||
* the type
|
||||
* @return the created queue
|
||||
*/
|
||||
public static final <T> PriorityQueue<T> newPriorityQueue() {
|
||||
return new PriorityQueue<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new reference queue of type <tt>T</tt>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the {@link ReferenceQueue}
|
||||
*
|
||||
* @return the created queue
|
||||
*/
|
||||
public static final <T> ReferenceQueue<T> newReferenceQueue() {
|
||||
return new ReferenceQueue<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new map.
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
* @return the new map
|
||||
*/
|
||||
public static final <K, V> Map<K, V> newMap() {
|
||||
return new FastMap<K, V>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new weak map.
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @param <V>
|
||||
* the value type
|
||||
* @return the new map
|
||||
*/
|
||||
public static final <K, V> Map<K, V> newWeakMap() {
|
||||
return new WeakHashMap<K, V>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
/**
|
||||
* Class with basic method implementation for areas.<br>
|
||||
* If possible it should be subclassed. <br>
|
||||
* In other case {@link Area} should be implemented directly
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public abstract class AbstractArea implements Area {
|
||||
/**
|
||||
* Minimal z of area
|
||||
*/
|
||||
private final int minZ;
|
||||
|
||||
/**
|
||||
* Maximal Z of area
|
||||
*/
|
||||
private final int maxZ;
|
||||
|
||||
/**
|
||||
* Creates new AbstractArea with min and max z
|
||||
*
|
||||
* @param minZ
|
||||
* min z
|
||||
* @param maxZ
|
||||
* max z
|
||||
*/
|
||||
protected AbstractArea(int minZ, int maxZ) {
|
||||
if (minZ > maxZ) {
|
||||
throw new IllegalArgumentException("minZ(" + minZ + ") > maxZ("
|
||||
+ maxZ + ")");
|
||||
}
|
||||
this.minZ = minZ;
|
||||
this.maxZ = maxZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInside2D(Point point) {
|
||||
return isInside2D(point.x, point.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInside3D(Point3D point) {
|
||||
return isInside3D(point.getX(), point.getY(), point.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInside3D(int x, int y, int z) {
|
||||
return isInsideZ(z) && isInside2D(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsideZ(Point3D point) {
|
||||
return isInsideZ(point.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsideZ(int z) {
|
||||
return z >= getMinZ() && z <= getMaxZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance2D(Point point) {
|
||||
return getDistance2D(point.x, point.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance3D(Point3D point) {
|
||||
return getDistance3D(point.getX(), point.getY(), point.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getClosestPoint(Point point) {
|
||||
return getClosestPoint(point.x, point.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point3D getClosestPoint(Point3D point) {
|
||||
return getClosestPoint(point.getX(), point.getY(), point.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point3D getClosestPoint(int x, int y, int z) {
|
||||
Point closest2d = getClosestPoint(x, y);
|
||||
|
||||
int zCoord;
|
||||
|
||||
if (isInsideZ(z)) {
|
||||
zCoord = z;
|
||||
} else if (z < getMinZ()) {
|
||||
zCoord = getMinZ();
|
||||
} else {
|
||||
zCoord = getMaxZ();
|
||||
}
|
||||
|
||||
return new Point3D(closest2d.x, closest2d.y, zCoord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinZ() {
|
||||
return minZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxZ() {
|
||||
return maxZ;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
/**
|
||||
* Basic interface for all areas.<br>
|
||||
* It should be implemented in different ways for performance reasons.<br>
|
||||
* For instance, we don't need complex math for squares or circles, but we need
|
||||
* it for more complex polygons.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface Area {
|
||||
/**
|
||||
* Returns true if point is inside area ignoring z value
|
||||
*
|
||||
* @param point
|
||||
* point to check
|
||||
* @return point is inside or not
|
||||
*/
|
||||
boolean isInside2D(Point point);
|
||||
|
||||
/**
|
||||
* Returns true if coords are inside area ignoring z value
|
||||
*
|
||||
* @param x
|
||||
* x coord
|
||||
* @param y
|
||||
* y coord
|
||||
* @return coords are inside or not
|
||||
*/
|
||||
boolean isInside2D(int x, int y);
|
||||
|
||||
/**
|
||||
* Returns true if point is inside area
|
||||
*
|
||||
* @param point
|
||||
* point to check
|
||||
* @return true if point is inside
|
||||
*/
|
||||
boolean isInside3D(Point3D point);
|
||||
|
||||
/**
|
||||
* Returns true if coors are inside area
|
||||
*
|
||||
* @param x
|
||||
* x coord
|
||||
* @param y
|
||||
* y coord
|
||||
* @param z
|
||||
* z coord
|
||||
* @return true if coords are inside
|
||||
*/
|
||||
boolean isInside3D(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Checks if z coord is insize
|
||||
*
|
||||
* @param point
|
||||
* point to check
|
||||
* @return is z inside or not
|
||||
*/
|
||||
boolean isInsideZ(Point3D point);
|
||||
|
||||
/**
|
||||
* Checks is z coord is inside
|
||||
*
|
||||
* @param z
|
||||
* z coord
|
||||
* @return is z inside or not
|
||||
*/
|
||||
boolean isInsideZ(int z);
|
||||
|
||||
/**
|
||||
* Returns distance from point to closest point of this area ignoring z.<br>
|
||||
* Returns 0 if point is inside area.
|
||||
*
|
||||
* @param point
|
||||
* point to calculate distance from
|
||||
* @return distance or 0 if is inside area
|
||||
*/
|
||||
double getDistance2D(Point point);
|
||||
|
||||
/**
|
||||
* Returns distance from point to closest point of this area ignoring z.<br>
|
||||
* Returns 0 point is inside area.
|
||||
*
|
||||
* @param x
|
||||
* x coord
|
||||
* @param y
|
||||
* y coord
|
||||
* @return distance or 0 if is inside area
|
||||
*/
|
||||
double getDistance2D(int x, int y);
|
||||
|
||||
/**
|
||||
* Returns distance from point to this area.<br>
|
||||
* Returns 0 if is inside.
|
||||
*
|
||||
* @param point
|
||||
* point to check
|
||||
* @return distance or 0 if is inside
|
||||
*/
|
||||
double getDistance3D(Point3D point);
|
||||
|
||||
/**
|
||||
* Returns distance from coords to this area
|
||||
*
|
||||
* @param x
|
||||
* x coord
|
||||
* @param y
|
||||
* y coord
|
||||
* @param z
|
||||
* z coord
|
||||
* @return distance or 0 if is inside
|
||||
*/
|
||||
double getDistance3D(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Returns closest point of area to given point.<br>
|
||||
* Returns point with coords = point arg if is inside
|
||||
*
|
||||
* @param point
|
||||
* point to check
|
||||
* @return closest point
|
||||
*/
|
||||
Point getClosestPoint(Point point);
|
||||
|
||||
/**
|
||||
* Returns closest point of area to given coords.<br>
|
||||
* Returns point with coords x and y if coords are inside
|
||||
*
|
||||
* @param x
|
||||
* x coord
|
||||
* @param y
|
||||
* y coord
|
||||
* @return closest point
|
||||
*/
|
||||
Point getClosestPoint(int x, int y);
|
||||
|
||||
/**
|
||||
* Returns closest point of area to given point.<br>
|
||||
* Works exactly like {@link #getClosestPoint(int, int)} if
|
||||
* {@link #isInsideZ(int)} returns true.<br>
|
||||
* In other case closest z edge is set as z coord.
|
||||
*
|
||||
* @param point
|
||||
* point to check
|
||||
* @return closest point of area to point
|
||||
*/
|
||||
Point3D getClosestPoint(Point3D point);
|
||||
|
||||
/**
|
||||
* Returns closest point of area to given coords.<br>
|
||||
* Works exactly like {@link #getClosestPoint(int, int)} if
|
||||
* {@link #isInsideZ(int)} returns true.<br>
|
||||
* In other case closest z edge is set as z coord.
|
||||
*
|
||||
* @param x
|
||||
* x coord
|
||||
* @param y
|
||||
* y coord
|
||||
* @param z
|
||||
* z coord
|
||||
* @return closest point of area to point
|
||||
*/
|
||||
Point3D getClosestPoint(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Return minimal z of this area
|
||||
*
|
||||
* @return minimal z of this area
|
||||
*/
|
||||
int getMinZ();
|
||||
|
||||
/**
|
||||
* Returns maximal z of this area
|
||||
*
|
||||
* @return maximal z of this area
|
||||
*/
|
||||
int getMaxZ();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
import org.apache.commons.math.geometry.Vector3D;
|
||||
|
||||
/**
|
||||
* Represents an coordinate in the game world.
|
||||
* <p>
|
||||
* Each coordinate has 3 points: x, y and z.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class Coordinate {
|
||||
/**
|
||||
* The backing vector of this Coordinate
|
||||
*/
|
||||
protected final Vector3D vector;
|
||||
|
||||
/**
|
||||
* Creates a new coordinate
|
||||
*
|
||||
* @param x
|
||||
* the x point
|
||||
* @param y
|
||||
* the y point
|
||||
* @param z
|
||||
* the z point
|
||||
*/
|
||||
protected Coordinate(int x, int y, int z) {
|
||||
this.vector = new Vector3D(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x cord
|
||||
*/
|
||||
public int getX() {
|
||||
return (int) vector.getX();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the y cord
|
||||
*/
|
||||
public int getY() {
|
||||
return (int) vector.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the z cord
|
||||
*/
|
||||
public int getZ() {
|
||||
return (int) vector.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the distance between <tt>this</tt> coordinate and
|
||||
* <tt>other</tt>
|
||||
*
|
||||
* @param other
|
||||
* the other coordinate
|
||||
* @return the calculated distance
|
||||
*/
|
||||
public double getDistance(Coordinate other) {
|
||||
return Vector3D.distance(vector, other.vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the squared distance between <tt>this</tt> coordinate and
|
||||
* <tt>other</tt>. This method is slighter faster then
|
||||
* {@link #getDistance(Coordinate)}.
|
||||
*
|
||||
* @param other
|
||||
* the other coordinate
|
||||
* @return the calculated distance
|
||||
*/
|
||||
public double getDistanceSquared(Coordinate other) {
|
||||
return Vector3D.distanceSq(vector, other.vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the 3 points
|
||||
*
|
||||
* @param x
|
||||
* the x point
|
||||
* @param y
|
||||
* the y point
|
||||
* @param z
|
||||
* the z point
|
||||
* @return the new {@link Coordinate} object created
|
||||
*/
|
||||
public static Coordinate fromXYZ(int x, int y, int z) {
|
||||
return new Coordinate(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Coordinate [" + vector + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Point3D} representing this {@link Coordinate}
|
||||
*/
|
||||
public Point3D toPoint() {
|
||||
return new Point3D(this, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
import com.l2jserver.util.MathUtil;
|
||||
|
||||
/**
|
||||
* This class implements cylinder area
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class CylinderArea extends AbstractArea {
|
||||
/**
|
||||
* Center of cylinder
|
||||
*/
|
||||
private final int centerX;
|
||||
/**
|
||||
* Center of cylinder
|
||||
*/
|
||||
private final int centerY;
|
||||
/**
|
||||
* Cylinder radius
|
||||
*/
|
||||
private final int radius;
|
||||
|
||||
/**
|
||||
* Creates new cylinder with given radius
|
||||
*
|
||||
* @param center
|
||||
* center of the circle
|
||||
* @param radius
|
||||
* radius of the circle
|
||||
* @param minZ
|
||||
* min z
|
||||
* @param maxZ
|
||||
* max z
|
||||
*/
|
||||
public CylinderArea(Point center, int radius, int minZ, int maxZ) {
|
||||
this(center.x, center.y, radius, minZ, maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new cylider with given radius
|
||||
*
|
||||
* @param x
|
||||
* center coord
|
||||
* @param y
|
||||
* center coord
|
||||
* @param radius
|
||||
* radius of the circle
|
||||
* @param minZ
|
||||
* min z
|
||||
* @param maxZ
|
||||
* max z
|
||||
*/
|
||||
public CylinderArea(int x, int y, int radius, int minZ, int maxZ) {
|
||||
super(minZ, maxZ);
|
||||
this.centerX = x;
|
||||
this.centerY = y;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInside2D(int x, int y) {
|
||||
return MathUtil.getDistance(centerX, centerY, x, y) < radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance2D(int x, int y) {
|
||||
if (isInside2D(x, y)) {
|
||||
return 0;
|
||||
} else {
|
||||
return Math.abs(MathUtil.getDistance(centerX, centerY, x, y)
|
||||
- radius);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance3D(int x, int y, int z) {
|
||||
if (isInside3D(x, y, z)) {
|
||||
return 0;
|
||||
} else if (isInsideZ(z)) {
|
||||
return getDistance2D(x, y);
|
||||
} else {
|
||||
if (z < getMinZ()) {
|
||||
return MathUtil.getDistance(centerX, centerY, getMinZ(), x, y,
|
||||
z);
|
||||
} else {
|
||||
return MathUtil.getDistance(centerX, centerY, getMaxZ(), x, y,
|
||||
z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getClosestPoint(int x, int y) {
|
||||
if (isInside2D(x, y)) {
|
||||
return new Point(x, y);
|
||||
} else {
|
||||
int vX = x - this.centerX;
|
||||
int vY = y - this.centerY;
|
||||
double magV = MathUtil.getDistance(centerX, centerY, x, y);
|
||||
double pointX = centerX + vX / magV * radius;
|
||||
double pointY = centerY + vY / magV * radius;
|
||||
return new Point((int) Math.round(pointX), (int) Math.round(pointY));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
/**
|
||||
* An two dimensional point
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class Point {
|
||||
/**
|
||||
* The X axis
|
||||
*/
|
||||
public final int x;
|
||||
/**
|
||||
* The Y axis
|
||||
*/
|
||||
public final int y;
|
||||
|
||||
/**
|
||||
* Creates a new two dimensional point
|
||||
*
|
||||
* @param x
|
||||
* the x axis
|
||||
* @param y
|
||||
* the y axis
|
||||
*/
|
||||
public Point(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x
|
||||
*/
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the y
|
||||
*/
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new point from X and Y axis
|
||||
*
|
||||
* @param x
|
||||
* the x axis
|
||||
* @param y
|
||||
* the y axis
|
||||
* @return the new created Point
|
||||
*/
|
||||
public static final Point fromXY(int x, int y) {
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
/**
|
||||
* An point is composed of an Coordinate and an angle. The angle represents the
|
||||
* facing angle of the point, that is, the direction the point is "looking".
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class Point3D extends Point {
|
||||
/**
|
||||
* The point coordinate
|
||||
*/
|
||||
protected final Coordinate coordinate;
|
||||
/**
|
||||
* The point angle
|
||||
*/
|
||||
protected final double angle;
|
||||
|
||||
/**
|
||||
* Creates a new point
|
||||
*
|
||||
* @param coordinate
|
||||
* the coordinate
|
||||
* @param angle
|
||||
* the angle
|
||||
*/
|
||||
public Point3D(Coordinate coordinate, double angle) {
|
||||
super(coordinate.getX(), coordinate.getY());
|
||||
this.coordinate = coordinate;
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new point with 3 axis
|
||||
*
|
||||
* @param x
|
||||
* the x axis
|
||||
* @param y
|
||||
* the y axis
|
||||
* @param z
|
||||
* the z axis
|
||||
*/
|
||||
public Point3D(int x, int y, int z) {
|
||||
this(new Coordinate(x, y, z), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x
|
||||
* @see com.l2jserver.util.geometry.Coordinate#getX()
|
||||
*/
|
||||
@Override
|
||||
public int getX() {
|
||||
return coordinate.getX();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the y
|
||||
* @see com.l2jserver.util.geometry.Coordinate#getY()
|
||||
*/
|
||||
@Override
|
||||
public int getY() {
|
||||
return coordinate.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the z
|
||||
* @see com.l2jserver.util.geometry.Coordinate#getZ()
|
||||
*/
|
||||
public int getZ() {
|
||||
return coordinate.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other
|
||||
* the other coordinate
|
||||
* @return the distance
|
||||
* @see com.l2jserver.util.geometry.Coordinate#getDistance(com.l2jserver.util.geometry.Coordinate)
|
||||
*/
|
||||
public double getDistance(Coordinate other) {
|
||||
return coordinate.getDistance(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other
|
||||
* the other point
|
||||
* @return the distance
|
||||
* @see com.l2jserver.util.geometry.Coordinate#getDistance(com.l2jserver.util.geometry.Coordinate)
|
||||
*/
|
||||
public double getDistance(Point3D other) {
|
||||
return coordinate.getDistance(other.coordinate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the angle
|
||||
*/
|
||||
public double getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the coordinate
|
||||
*/
|
||||
public Coordinate getCoordinate() {
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the 3 points and an angle
|
||||
*
|
||||
* @param x
|
||||
* the x point
|
||||
* @param y
|
||||
* the y point
|
||||
* @param z
|
||||
* the z point
|
||||
* @param angle
|
||||
* the angle
|
||||
* @return the new {@link Point3D} object created
|
||||
*/
|
||||
public static final Point3D fromXYZA(int x, int y, int z, double angle) {
|
||||
return new Point3D(Coordinate.fromXYZ(x, y, z), angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance from the 3 points. The angle will be zero.
|
||||
*
|
||||
* @param x
|
||||
* the x point
|
||||
* @param y
|
||||
* the y point
|
||||
* @param z
|
||||
* the z point
|
||||
* @return the new {@link Point3D} object created
|
||||
*/
|
||||
public static final Point3D fromXYZ(int x, int y, int z) {
|
||||
return fromXYZA(x, y, z, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
import java.awt.Polygon;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.l2jserver.util.MathUtil;
|
||||
|
||||
/**
|
||||
* Area of free form
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class PolygonArea extends AbstractArea {
|
||||
/**
|
||||
* Collection of x points
|
||||
*/
|
||||
private final int[] xPoints;
|
||||
|
||||
/**
|
||||
* Collection of y points
|
||||
*/
|
||||
private final int[] yPoints;
|
||||
|
||||
/**
|
||||
* Polygon used to calculate isInside()
|
||||
*/
|
||||
private final Polygon poly;
|
||||
|
||||
/**
|
||||
* Creates new area from given points
|
||||
*
|
||||
* @param points
|
||||
* list of points
|
||||
* @param zMin
|
||||
* minimal z
|
||||
* @param zMax
|
||||
* maximal z
|
||||
*/
|
||||
public PolygonArea(Collection<Point> points, int zMin, int zMax) {
|
||||
this(points.toArray(new Point[points.size()]), zMin, zMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new area from given points
|
||||
*
|
||||
* @param points
|
||||
* list of points
|
||||
* @param zMin
|
||||
* minimal z
|
||||
* @param zMax
|
||||
* maximal z
|
||||
*/
|
||||
public PolygonArea(Point[] points, int zMin, int zMax) {
|
||||
super(zMin, zMax);
|
||||
|
||||
if (points.length < 3) {
|
||||
throw new IllegalArgumentException(
|
||||
"Not enough points, needed at least 3 but got "
|
||||
+ points.length);
|
||||
}
|
||||
|
||||
this.xPoints = new int[points.length];
|
||||
this.yPoints = new int[points.length];
|
||||
|
||||
Polygon polygon = new Polygon();
|
||||
for (int i = 0, n = points.length; i < n; i++) {
|
||||
Point p = points[i];
|
||||
polygon.addPoint(p.x, p.y);
|
||||
xPoints[i] = p.x;
|
||||
yPoints[i] = p.y;
|
||||
}
|
||||
this.poly = polygon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInside2D(int x, int y) {
|
||||
return poly.contains(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance2D(int x, int y) {
|
||||
if (isInside2D(x, y)) {
|
||||
return 0;
|
||||
} else {
|
||||
Point cp = getClosestPoint(x, y);
|
||||
return MathUtil.getDistance(cp.x, cp.y, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance3D(int x, int y, int z) {
|
||||
if (isInside3D(x, y, z)) {
|
||||
return 0;
|
||||
} else if (isInsideZ(z)) {
|
||||
return getDistance2D(x, y);
|
||||
} else {
|
||||
Point3D cp = getClosestPoint(x, y, z);
|
||||
return MathUtil.getDistance(cp.getX(), cp.getY(), cp.getZ(), x, y,
|
||||
z);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getClosestPoint(int x, int y) {
|
||||
Point closestPoint = null;
|
||||
double closestDistance = 0;
|
||||
|
||||
for (int i = 0; i < xPoints.length; i++) {
|
||||
int nextIndex = i + 1;
|
||||
if (nextIndex == xPoints.length) {
|
||||
nextIndex = 0;
|
||||
}
|
||||
|
||||
int p1x = xPoints[i];
|
||||
int p1y = yPoints[i];
|
||||
int p2x = xPoints[nextIndex];
|
||||
int p2y = yPoints[nextIndex];
|
||||
|
||||
Point point = MathUtil.getClosestPointOnSegment(p1x, p1y, p2x, p2y,
|
||||
x, y);
|
||||
|
||||
if (closestPoint == null) {
|
||||
closestPoint = point;
|
||||
closestDistance = MathUtil.getDistance(closestPoint.x,
|
||||
closestPoint.y, x, y);
|
||||
} else {
|
||||
double newDistance = MathUtil.getDistance(point.x, point.y, x,
|
||||
y);
|
||||
if (newDistance < closestDistance) {
|
||||
closestPoint = point;
|
||||
closestDistance = newDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestPoint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.geometry;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import com.l2jserver.util.MathUtil;
|
||||
|
||||
/**
|
||||
* Rectangle area, most wide spread in the game
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class RectangleArea extends AbstractArea {
|
||||
/**
|
||||
* Min x point
|
||||
*/
|
||||
private final int minX;
|
||||
|
||||
/**
|
||||
* Max x point
|
||||
*/
|
||||
private final int maxX;
|
||||
|
||||
/**
|
||||
* Min y point
|
||||
*/
|
||||
private final int minY;
|
||||
|
||||
/**
|
||||
* Max y point
|
||||
*/
|
||||
private final int maxY;
|
||||
|
||||
/**
|
||||
* Creates new area from given points. Point order doesn't matter
|
||||
*
|
||||
* @param p1
|
||||
* point
|
||||
* @param p2
|
||||
* point
|
||||
* @param p3
|
||||
* point
|
||||
* @param p4
|
||||
* point
|
||||
* @param minZ
|
||||
* minimal z
|
||||
* @param maxZ
|
||||
* maximal z
|
||||
*/
|
||||
public RectangleArea(Point p1, Point p2, Point p3, Point p4, int minZ,
|
||||
int maxZ) {
|
||||
super(minZ, maxZ);
|
||||
|
||||
// we should use a better way to do this
|
||||
Rectangle r = new Rectangle();
|
||||
r.add(new java.awt.Point(p1.x, p1.y));
|
||||
r.add(new java.awt.Point(p2.x, p2.y));
|
||||
r.add(new java.awt.Point(p3.x, p3.y));
|
||||
r.add(new java.awt.Point(p4.x, p4.y));
|
||||
|
||||
minX = (int) r.getMinX();
|
||||
maxX = (int) r.getMaxX();
|
||||
minY = (int) r.getMinY();
|
||||
maxY = (int) r.getMaxY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new are from given coords
|
||||
*
|
||||
* @param minX
|
||||
* mimal x point
|
||||
* @param minY
|
||||
* minimal y point
|
||||
* @param maxX
|
||||
* maximal x point
|
||||
* @param maxY
|
||||
* maximal y point
|
||||
* @param minZ
|
||||
* minimal z point
|
||||
* @param maxZ
|
||||
* maximal z point
|
||||
*/
|
||||
public RectangleArea(int minX, int minY, int maxX, int maxY, int minZ,
|
||||
int maxZ) {
|
||||
super(minZ, maxZ);
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInside2D(int x, int y) {
|
||||
return x >= minX && x <= maxX && y >= minY && y <= maxY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance2D(int x, int y) {
|
||||
if (isInside2D(x, y)) {
|
||||
return 0;
|
||||
} else {
|
||||
Point cp = getClosestPoint(x, y);
|
||||
return MathUtil.getDistance(x, y, cp.x, cp.y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance3D(int x, int y, int z) {
|
||||
if (isInside3D(x, y, z)) {
|
||||
return 0;
|
||||
} else if (isInsideZ(z)) {
|
||||
return getDistance2D(x, y);
|
||||
} else {
|
||||
Point3D cp = getClosestPoint(x, y, z);
|
||||
return MathUtil.getDistance(x, y, z, cp.getX(), cp.getY(),
|
||||
cp.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getClosestPoint(int x, int y) {
|
||||
|
||||
if (isInside2D(x, y)) {
|
||||
return new Point(x, y);
|
||||
} else {
|
||||
// bottom edge
|
||||
Point closestPoint = MathUtil.getClosestPointOnSegment(minX, minY,
|
||||
maxX, minY, x, y);
|
||||
double distance = MathUtil.getDistance(x, y, closestPoint.x,
|
||||
closestPoint.y);
|
||||
|
||||
// top edge
|
||||
Point cp = MathUtil.getClosestPointOnSegment(minX, maxY, maxX,
|
||||
maxY, x, y);
|
||||
double d = MathUtil.getDistance(x, y, cp.x, cp.y);
|
||||
if (d < distance) {
|
||||
closestPoint = cp;
|
||||
distance = d;
|
||||
}
|
||||
|
||||
// left edge
|
||||
cp = MathUtil
|
||||
.getClosestPointOnSegment(minX, minY, minX, maxY, x, y);
|
||||
d = MathUtil.getDistance(x, y, cp.x, cp.y);
|
||||
if (d < distance) {
|
||||
closestPoint = cp;
|
||||
distance = d;
|
||||
}
|
||||
|
||||
// Right edge
|
||||
cp = MathUtil
|
||||
.getClosestPointOnSegment(maxX, minY, maxX, maxY, x, y);
|
||||
d = MathUtil.getDistance(x, y, cp.x, cp.y);
|
||||
if (d < distance) {
|
||||
closestPoint = cp;
|
||||
// distance = d;
|
||||
}
|
||||
|
||||
return closestPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer;
|
||||
|
||||
/**
|
||||
* An transformer can transform an {@link Object} into an {@link String} and the
|
||||
* {@link String} back to an equivalent object.
|
||||
*
|
||||
* @param <T>
|
||||
* the transformed type
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface Transformer<T> {
|
||||
/**
|
||||
* Transform the object in a string
|
||||
*
|
||||
* @param value
|
||||
* the object
|
||||
* @return the string of the object
|
||||
*/
|
||||
String transform(T value);
|
||||
|
||||
/**
|
||||
* Untransforms the string back to an object
|
||||
*
|
||||
* @param value
|
||||
* the string
|
||||
* @return the object
|
||||
*/
|
||||
T untransform(String value);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.l2jserver.util.transformer.impl.BooleanTransformer;
|
||||
import com.l2jserver.util.transformer.impl.ByteTransformer;
|
||||
import com.l2jserver.util.transformer.impl.ClassTransformer;
|
||||
import com.l2jserver.util.transformer.impl.DoubleTransformer;
|
||||
import com.l2jserver.util.transformer.impl.FileTransformer;
|
||||
import com.l2jserver.util.transformer.impl.FloatTransformer;
|
||||
import com.l2jserver.util.transformer.impl.InetSocketAddressTransformer;
|
||||
import com.l2jserver.util.transformer.impl.IntegerTransformer;
|
||||
import com.l2jserver.util.transformer.impl.LongTransformer;
|
||||
import com.l2jserver.util.transformer.impl.PathTransformer;
|
||||
import com.l2jserver.util.transformer.impl.ShortTransformer;
|
||||
import com.l2jserver.util.transformer.impl.URITransformer;
|
||||
import com.l2jserver.util.transformer.impl.URLTransformer;
|
||||
|
||||
/**
|
||||
* The {@link TransformerFactory} return the transformer instance for any given
|
||||
* type.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class TransformerFactory {
|
||||
/**
|
||||
* return the transformer instance the given <tt>type</tt>.
|
||||
*
|
||||
* @param type
|
||||
* the type
|
||||
* @return the transformer
|
||||
*/
|
||||
public static final Transformer<?> getTransfromer(Class<?> type) {
|
||||
if (type == Byte.class || type == Byte.TYPE) {
|
||||
return ByteTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Short.class || type == Short.TYPE) {
|
||||
return ShortTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Integer.class || type == Integer.TYPE) {
|
||||
return IntegerTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Long.class || type == Long.TYPE) {
|
||||
return LongTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Float.class || type == Float.TYPE) {
|
||||
return FloatTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Double.class || type == Double.TYPE) {
|
||||
return DoubleTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Boolean.class || type == Boolean.TYPE) {
|
||||
return BooleanTransformer.SHARED_INSTANCE;
|
||||
} else if (type == InetSocketAddress.class) {
|
||||
return InetSocketAddressTransformer.SHARED_INSTANCE;
|
||||
} else if (type == File.class) {
|
||||
return FileTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Class.class) {
|
||||
return ClassTransformer.SHARED_INSTANCE;
|
||||
} else if (type == URI.class) {
|
||||
return URITransformer.SHARED_INSTANCE;
|
||||
} else if (type == URL.class) {
|
||||
return URLTransformer.SHARED_INSTANCE;
|
||||
} else if (type == Path.class) {
|
||||
return PathTransformer.SHARED_INSTANCE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Boolean} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class BooleanTransformer implements Transformer<Boolean> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final BooleanTransformer SHARED_INSTANCE = new BooleanTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Boolean value) {
|
||||
return (value ? "true" : "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean untransform(String value) {
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ByteTransformer implements Transformer<Byte> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final ByteTransformer SHARED_INSTANCE = new ByteTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Byte value) {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte untransform(String value) {
|
||||
return Byte.decode(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Class} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ClassTransformer implements Transformer<Class<?>> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final ClassTransformer SHARED_INSTANCE = new ClassTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Class<?> value) {
|
||||
return value.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> untransform(String value) {
|
||||
try {
|
||||
return Class.forName(value);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class DoubleTransformer implements Transformer<Double> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final DoubleTransformer SHARED_INSTANCE = new DoubleTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Double value) {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double untransform(String value) {
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class FileTransformer implements Transformer<File> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final FileTransformer SHARED_INSTANCE = new FileTransformer();
|
||||
|
||||
/**
|
||||
* The root to resolve relative files
|
||||
*/
|
||||
private final File root = new File("./");
|
||||
|
||||
@Override
|
||||
public String transform(File value) {
|
||||
return value.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File untransform(String value) {
|
||||
return new File(root, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class FloatTransformer implements Transformer<Float> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final FloatTransformer SHARED_INSTANCE = new FloatTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Float value) {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float untransform(String value) {
|
||||
return Float.parseFloat(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class InetSocketAddressTransformer implements
|
||||
Transformer<InetSocketAddress> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final InetSocketAddressTransformer SHARED_INSTANCE = new InetSocketAddressTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(InetSocketAddress value) {
|
||||
return value.getHostName() + ":" + value.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress untransform(String value) {
|
||||
final String[] pieces = value.split(":");
|
||||
if (pieces.length != 2)
|
||||
return null;
|
||||
return new InetSocketAddress(pieces[0], Integer.parseInt(pieces[1]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class IntegerTransformer implements Transformer<Integer> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final IntegerTransformer SHARED_INSTANCE = new IntegerTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Integer value) {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer untransform(String value) {
|
||||
return Integer.decode(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Long} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class LongTransformer implements Transformer<Long> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final LongTransformer SHARED_INSTANCE = new LongTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Long value) {
|
||||
return Long.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long untransform(String value) {
|
||||
return Long.decode(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Path} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class PathTransformer implements Transformer<Path> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final PathTransformer SHARED_INSTANCE = new PathTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Path value) {
|
||||
if (value == null)
|
||||
return "";
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path untransform(String value) {
|
||||
return Paths.get(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link Integer} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class ShortTransformer implements Transformer<Short> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final ShortTransformer SHARED_INSTANCE = new ShortTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(Short value) {
|
||||
return Short.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short untransform(String value) {
|
||||
return Short.decode(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link URI} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class URITransformer implements Transformer<URI> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final URITransformer SHARED_INSTANCE = new URITransformer();
|
||||
|
||||
@Override
|
||||
public String transform(URI value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI untransform(String value) {
|
||||
return URI.create(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util.transformer.impl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import com.l2jserver.util.transformer.Transformer;
|
||||
|
||||
/**
|
||||
* Transform an {@link URI} into an string.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class URLTransformer implements Transformer<URL> {
|
||||
/**
|
||||
* This transformer shared instance
|
||||
*/
|
||||
public static final URLTransformer SHARED_INSTANCE = new URLTransformer();
|
||||
|
||||
@Override
|
||||
public String transform(URL value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL untransform(String value) {
|
||||
try {
|
||||
return new URL(value);
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.model.id.allocator;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.l2jserver.model.id.object.allocator.BitSetIDAllocator;
|
||||
import com.l2jserver.model.id.object.allocator.IDAllocator;
|
||||
import com.l2jserver.model.id.object.allocator.IDAllocatorException;
|
||||
|
||||
public class BitSetIDAllocatorTest {
|
||||
private final BitSetIDAllocator allocator = new BitSetIDAllocator();
|
||||
|
||||
@Before
|
||||
public void tearUp() {
|
||||
allocator.init();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllocate() {
|
||||
final int id1 = allocator.allocate();
|
||||
final int id2 = allocator.allocate();
|
||||
assertFalse(id1 == id2);
|
||||
assertEquals(IDAllocator.FIRST_ID, id1);
|
||||
assertEquals(IDAllocator.FIRST_ID + 1, id2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllocateRestore() {
|
||||
final int id1 = IDAllocator.FIRST_ID;
|
||||
final int id2 = IDAllocator.FIRST_ID + 1;
|
||||
|
||||
allocator.allocate(id1);
|
||||
allocator.allocate(id2);
|
||||
|
||||
int id3 = allocator.allocate();
|
||||
|
||||
assertFalse(id1 == id3);
|
||||
assertFalse(id2 == id3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllocateMany() {
|
||||
for (int i = 0; i < 100 * 1000; i++) {
|
||||
allocator.allocate();
|
||||
}
|
||||
assertEquals(100000, allocator.getAllocatedIDs());
|
||||
}
|
||||
|
||||
@Test(expected = IDAllocatorException.class)
|
||||
public void testAllocateAlreadyAllocated() {
|
||||
final int id1 = allocator.allocate();
|
||||
allocator.allocate(id1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRelease() {
|
||||
final int id = allocator.allocate();
|
||||
allocator.release(id);
|
||||
}
|
||||
|
||||
@Test(expected = IDAllocatorException.class)
|
||||
public void testReleaseUnalloc() {
|
||||
allocator.release(IDAllocator.FIRST_ID);
|
||||
}
|
||||
}
|
||||
99
l2jserver2-common/src/test/java/com/l2jserver/service/cache/SimpleCacheServiceTest.java
vendored
Normal file
99
l2jserver2-common/src/test/java/com/l2jserver/service/cache/SimpleCacheServiceTest.java
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
|
||||
public class SimpleCacheServiceTest {
|
||||
private final EhCacheService cacheService = new EhCacheService();
|
||||
|
||||
@Before
|
||||
public void tearUp() throws ServiceStartException {
|
||||
cacheService.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoArgs() {
|
||||
final TestCacheable cached = cacheService.decorate(TestCacheable.class,
|
||||
new TestCacheableInstance());
|
||||
int output1 = cached.random();
|
||||
int output2 = cached.random();
|
||||
Assert.assertEquals(output1, output2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameArgs() {
|
||||
final TestCacheable cached = cacheService.decorate(TestCacheable.class,
|
||||
new TestCacheableInstance());
|
||||
int output1 = cached.random(10);
|
||||
int output2 = cached.random(10);
|
||||
Assert.assertEquals(output1, output2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentArgs() {
|
||||
final TestCacheable cached = cacheService.decorate(TestCacheable.class,
|
||||
new TestCacheableInstance());
|
||||
int output1 = cached.random(10);
|
||||
int output2 = cached.random(20);
|
||||
Assert.assertFalse(output1 == output2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreCaching() {
|
||||
final TestCacheable cached = cacheService.decorate(TestCacheable.class,
|
||||
new TestCacheableInstance());
|
||||
int output1 = cached.notCached();
|
||||
int output2 = cached.notCached();
|
||||
Assert.assertFalse(output1 == output2);
|
||||
}
|
||||
|
||||
public interface TestCacheable extends Cacheable {
|
||||
public int random();
|
||||
|
||||
public int random(int arg);
|
||||
|
||||
@IgnoreCaching
|
||||
public int notCached();
|
||||
}
|
||||
|
||||
public static class TestCacheableInstance implements TestCacheable {
|
||||
private final Random random = new Random();
|
||||
|
||||
@Override
|
||||
public int random() {
|
||||
return random.nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int random(int arg) {
|
||||
return random.nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int notCached() {
|
||||
return random.nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of l2jserver <l2jserver.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.configuration;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.configuration.XMLConfigurationService.ConfigurationXPath;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class XMLConfigurationServiceTest {
|
||||
/**
|
||||
* The {@link TestConfig} proxy
|
||||
*/
|
||||
private TestConfig config;
|
||||
|
||||
@Before
|
||||
public void tearUp() throws ServiceStartException {
|
||||
final XMLConfigurationService service = new XMLConfigurationService(
|
||||
new File("src/test/resources/test-config.xml"));
|
||||
service.start();
|
||||
config = service.get(TestConfig.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testString() throws ServiceStartException {
|
||||
Assert.assertEquals("test", config.getTestString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValue() throws ServiceStartException {
|
||||
Assert.assertEquals("default", config.getDefaultTestString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInteger() throws ServiceStartException {
|
||||
Assert.assertEquals(256, config.getTestInteger());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetter() throws ServiceStartException {
|
||||
config.setTestString("new-value");
|
||||
Assert.assertEquals("new-value", config.getTestString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullSetter() throws ServiceStartException {
|
||||
config.setTestString(null);
|
||||
Assert.assertEquals("test-default", config.getTestString());
|
||||
}
|
||||
|
||||
/**
|
||||
* The TestConfig interface
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public interface TestConfig extends Configuration {
|
||||
@ConfigurationPropertyGetter(defaultValue = "test-default")
|
||||
@ConfigurationXPath("/configuration/test/testvalue")
|
||||
String getTestString();
|
||||
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationXPath("/configuration/test/testvalue")
|
||||
void setTestString(String value);
|
||||
|
||||
@ConfigurationPropertyGetter(defaultValue = "default")
|
||||
@ConfigurationXPath("/configuration/test/nonexistentkey")
|
||||
String getDefaultTestString();
|
||||
|
||||
@ConfigurationPropertyGetter(defaultValue = "0")
|
||||
@ConfigurationXPath("/configuration/test/integer")
|
||||
int getTestInteger();
|
||||
|
||||
@ConfigurationPropertySetter
|
||||
@ConfigurationXPath("/configuration/test/integer")
|
||||
void setTestInteger(Integer n);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user