mirror of
https://github.com/Rogiel/l2jserver2
synced 2025-12-09 08:52:51 +00:00
Change-Id: I0cca627373c68d94025647f802a7fa6b419e0aad
This commit is contained in:
20
src/main/java/com/l2jserver/service/cache/CacheService.java
vendored
Normal file
20
src/main/java/com/l2jserver/service/cache/CacheService.java
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
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 {
|
||||
<T extends Cacheable> T decorate(Class<T> interfaceType, T instance);
|
||||
}
|
||||
5
src/main/java/com/l2jserver/service/cache/Cacheable.java
vendored
Normal file
5
src/main/java/com/l2jserver/service/cache/Cacheable.java
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
public interface Cacheable {
|
||||
|
||||
}
|
||||
16
src/main/java/com/l2jserver/service/cache/IgnoreCaching.java
vendored
Normal file
16
src/main/java/com/l2jserver/service/cache/IgnoreCaching.java
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
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;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
/**
|
||||
* Indicate to the proxy that this method should not be cached.
|
||||
*/
|
||||
public @interface IgnoreCaching {
|
||||
}
|
||||
94
src/main/java/com/l2jserver/service/cache/SimpleCacheService.java
vendored
Normal file
94
src/main/java/com/l2jserver/service/cache/SimpleCacheService.java
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.l2jserver.service.cache;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import com.l2jserver.service.ServiceStartException;
|
||||
import com.l2jserver.service.ServiceStopException;
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
|
||||
public class SimpleCacheService implements CacheService {
|
||||
private final Map<MethodInvocation, Object> cache = CollectionFactory
|
||||
.newWeakMap(MethodInvocation.class, Object.class);
|
||||
|
||||
@Override
|
||||
public void start() throws ServiceStartException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Cacheable> T decorate(final Class<T> interfaceType,
|
||||
final T instance) {
|
||||
if (!interfaceType.isInterface())
|
||||
return null;
|
||||
@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 = cache.get(invocation);
|
||||
if (result == null) {
|
||||
result = method.invoke(instance, args);
|
||||
cache.put(invocation, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws ServiceStopException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
private class MethodInvocation {
|
||||
private final Method method;
|
||||
private final Object[] args;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.l2jserver.service.game.world;
|
||||
|
||||
import com.l2jserver.model.id.ObjectID;
|
||||
import com.l2jserver.model.world.capability.Listenable;
|
||||
import com.l2jserver.model.world.event.WorldEvent;
|
||||
import com.l2jserver.model.world.event.WorldListener;
|
||||
|
||||
/**
|
||||
* This event dispatcher notify listeners that an certain event occured in their
|
||||
@@ -18,4 +21,64 @@ public interface WorldEventDispatcher {
|
||||
* the event
|
||||
*/
|
||||
void dispatch(WorldEvent event);
|
||||
|
||||
/**
|
||||
* Adds a new <tt>listener</tt> to <tt>object</tt>
|
||||
*
|
||||
* @param <E>
|
||||
* the event type
|
||||
* @param <L>
|
||||
* the listener type
|
||||
* @param object
|
||||
* the object to listen to
|
||||
* @param listener
|
||||
* the listener
|
||||
*/
|
||||
<E extends WorldEvent, L extends WorldListener<E>> void addListener(
|
||||
Listenable<L, E> object, WorldListener<E> listener);
|
||||
|
||||
/**
|
||||
* Adds a new <tt>listener</tt> to object with id <tt>id</tt>
|
||||
*
|
||||
* @param <E>
|
||||
* the event type
|
||||
* @param <L>
|
||||
* the listener type
|
||||
* @param id
|
||||
* the object id to listen to
|
||||
* @param listener
|
||||
* the listener
|
||||
*/
|
||||
<E extends WorldEvent, L extends WorldListener<E>> void addListener(
|
||||
ObjectID<? extends Listenable<L, E>> id, WorldListener<E> listener);
|
||||
|
||||
/**
|
||||
* Removes an existing <tt>listener</tt> from <tt>object</tt>
|
||||
*
|
||||
* @param <E>
|
||||
* the event type
|
||||
* @param <L>
|
||||
* the listener type
|
||||
* @param object
|
||||
* the object to listen to
|
||||
* @param listener
|
||||
* the listener
|
||||
*/
|
||||
<E extends WorldEvent, L extends WorldListener<E>> void removeListener(
|
||||
Listenable<L, E> object, WorldListener<E> listener);
|
||||
|
||||
/**
|
||||
* Removes an existing <tt>listener</tt> from the object with id <tt>id</tt>
|
||||
*
|
||||
* @param <E>
|
||||
* the event type
|
||||
* @param <L>
|
||||
* the listener type
|
||||
* @param id
|
||||
* the object id to listen to
|
||||
* @param listener
|
||||
* the listener
|
||||
*/
|
||||
<E extends WorldEvent, L extends WorldListener<E>> void removeListener(
|
||||
ObjectID<? extends Listenable<L, E>> id, WorldListener<E> listener);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
package com.l2jserver.service.game.world;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.l2jserver.model.id.ObjectID;
|
||||
import com.l2jserver.model.world.capability.Listenable;
|
||||
import com.l2jserver.model.world.event.WorldEvent;
|
||||
import com.l2jserver.model.world.event.WorldListener;
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
|
||||
/**
|
||||
* {@link WorldEventDispatcher} implementation
|
||||
@@ -8,8 +16,137 @@ import com.l2jserver.model.world.event.WorldEvent;
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public class WorldEventDispatcherImpl implements WorldEventDispatcher {
|
||||
private final Timer timer = new Timer();
|
||||
|
||||
private Queue<ListenerIDPair> listeners = CollectionFactory
|
||||
.newConcurrentQueue(ListenerIDPair.class);
|
||||
private Queue<WorldEvent> events = CollectionFactory
|
||||
.newConcurrentQueue(WorldEvent.class);
|
||||
|
||||
public WorldEventDispatcherImpl() {
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
final WorldEvent event = events.poll();
|
||||
if (event == null)
|
||||
return;
|
||||
try {
|
||||
doDispatch(event);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
}, 0, 50);
|
||||
}
|
||||
|
||||
public void dispatch(WorldEvent event) {
|
||||
// TODO implement threaded model
|
||||
event.dispatch();
|
||||
events.add(event);
|
||||
}
|
||||
|
||||
public void doDispatch(WorldEvent event) {
|
||||
final Listenable<?, ?>[] objects = event.getDispatchableObjects();
|
||||
for (final ListenerIDPair pair : listeners) {
|
||||
for (Listenable<?, ?> obj : objects) {
|
||||
if (obj == null)
|
||||
continue;
|
||||
if (!pair.testDispatch(obj.getID()))
|
||||
continue;
|
||||
try {
|
||||
if (pair.dispatch(event))
|
||||
continue;
|
||||
} catch (ClassCastException e) {
|
||||
}
|
||||
listeners.remove(pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E extends WorldEvent, L extends WorldListener<E>> void addListener(
|
||||
Listenable<L, E> object, WorldListener<E> listener) {
|
||||
listeners.add(new ListenerIDPair(object.getID(),
|
||||
(WorldListener<WorldEvent>) listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E extends WorldEvent, L extends WorldListener<E>> void addListener(
|
||||
ObjectID<? extends Listenable<L, E>> id, WorldListener<E> listener) {
|
||||
listeners.add(new ListenerIDPair(id,
|
||||
(WorldListener<WorldEvent>) listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E extends WorldEvent, L extends WorldListener<E>> void removeListener(
|
||||
Listenable<L, E> object, WorldListener<E> listener) {
|
||||
listeners.remove(new ListenerIDPair(object.getID(),
|
||||
(WorldListener<WorldEvent>) listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E extends WorldEvent, L extends WorldListener<E>> void removeListener(
|
||||
ObjectID<? extends Listenable<L, E>> id, WorldListener<E> listener) {
|
||||
listeners.remove(new ListenerIDPair(id,
|
||||
(WorldListener<WorldEvent>) listener));
|
||||
}
|
||||
|
||||
private class ListenerIDPair {
|
||||
private ObjectID<?> ID;
|
||||
private WorldListener<WorldEvent> listener;
|
||||
|
||||
public ListenerIDPair(ObjectID<?> ID, WorldListener<WorldEvent> listener) {
|
||||
super();
|
||||
this.ID = ID;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public boolean testDispatch(ObjectID<?> id) {
|
||||
return id.equals(this.ID);
|
||||
}
|
||||
|
||||
public boolean dispatch(WorldEvent e) {
|
||||
return listener.dispatch(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getOuterType().hashCode();
|
||||
result = prime * result + ((ID == null) ? 0 : ID.hashCode());
|
||||
result = prime * result
|
||||
+ ((listener == null) ? 0 : listener.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;
|
||||
ListenerIDPair other = (ListenerIDPair) obj;
|
||||
if (!getOuterType().equals(other.getOuterType()))
|
||||
return false;
|
||||
if (ID == null) {
|
||||
if (other.ID != null)
|
||||
return false;
|
||||
} else if (!ID.equals(other.ID))
|
||||
return false;
|
||||
if (listener == null) {
|
||||
if (other.listener != null)
|
||||
return false;
|
||||
} else if (!listener.equals(other.listener))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private WorldEventDispatcherImpl getOuterType() {
|
||||
return WorldEventDispatcherImpl.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.l2jserver.game.net.Lineage2Connection;
|
||||
import com.l2jserver.game.net.Lineage2PipelineFactory;
|
||||
import com.l2jserver.service.configuration.ConfigurationService;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.l2jserver.service.network;
|
||||
|
||||
import com.l2jserver.game.net.Lineage2Connection;
|
||||
import com.l2jserver.service.Service;
|
||||
|
||||
public interface NetworkService extends Service {
|
||||
|
||||
Reference in New Issue
Block a user