diff --git a/.classpath b/.classpath index a85f9973a..4186b9f3d 100644 --- a/.classpath +++ b/.classpath @@ -4,12 +4,11 @@ - - + - + diff --git a/data/contexts.xsd b/data/contexts.xsd new file mode 100644 index 000000000..3ab1ff159 --- /dev/null +++ b/data/contexts.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/scripts/com/l2jserver/script/DummyScript.java b/data/script/script/DummyScript.java similarity index 79% rename from data/scripts/com/l2jserver/script/DummyScript.java rename to data/script/script/DummyScript.java index 4d3ba44b7..00b3078e9 100644 --- a/data/scripts/com/l2jserver/script/DummyScript.java +++ b/data/script/script/DummyScript.java @@ -1,7 +1,7 @@ -package com.l2jserver.script; +package script; import com.l2jserver.model.world.capability.Scriptable; -import com.l2jserver.service.game.script.Script; +import com.l2jserver.service.game.scripting.Script; public class DummyScript implements Script { @Override diff --git a/data/template/com/l2jserver/model/template/armor/AbstractGradeAArmorTemplate.java b/data/template/script/template/armor/AbstractGradeAArmorTemplate.java similarity index 95% rename from data/template/com/l2jserver/model/template/armor/AbstractGradeAArmorTemplate.java rename to data/template/script/template/armor/AbstractGradeAArmorTemplate.java index bd9ddd956..e7c41c24d 100644 --- a/data/template/com/l2jserver/model/template/armor/AbstractGradeAArmorTemplate.java +++ b/data/template/script/template/armor/AbstractGradeAArmorTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.armor; +package script.template.armor; import com.l2jserver.model.id.TemplateID; import com.l2jserver.model.template.ArmorTemplate; diff --git a/data/template/com/l2jserver/model/template/armor/AbstractNoGradeArmorTemplate.java b/data/template/script/template/armor/AbstractNoGradeArmorTemplate.java similarity index 84% rename from data/template/com/l2jserver/model/template/armor/AbstractNoGradeArmorTemplate.java rename to data/template/script/template/armor/AbstractNoGradeArmorTemplate.java index f1605eade..ac48fe752 100644 --- a/data/template/com/l2jserver/model/template/armor/AbstractNoGradeArmorTemplate.java +++ b/data/template/script/template/armor/AbstractNoGradeArmorTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.armor; +package script.template.armor; import com.l2jserver.model.id.TemplateID; import com.l2jserver.model.template.ArmorTemplate; diff --git a/data/template/com/l2jserver/model/template/armor/Dummy2ArmorTemplate.java b/data/template/script/template/armor/Dummy2ArmorTemplate.java similarity index 95% rename from data/template/com/l2jserver/model/template/armor/Dummy2ArmorTemplate.java rename to data/template/script/template/armor/Dummy2ArmorTemplate.java index fa9cd703b..551cda815 100644 --- a/data/template/com/l2jserver/model/template/armor/Dummy2ArmorTemplate.java +++ b/data/template/script/template/armor/Dummy2ArmorTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.armor; +package script.template.armor; import com.l2jserver.model.world.capability.Attackable; import com.l2jserver.model.world.capability.Attacker; diff --git a/data/template/com/l2jserver/model/template/armor/DummyArmorTemplate.java b/data/template/script/template/armor/DummyArmorTemplate.java similarity index 94% rename from data/template/com/l2jserver/model/template/armor/DummyArmorTemplate.java rename to data/template/script/template/armor/DummyArmorTemplate.java index c51625e7a..54ccf22ab 100644 --- a/data/template/com/l2jserver/model/template/armor/DummyArmorTemplate.java +++ b/data/template/script/template/armor/DummyArmorTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.armor; +package script.template.armor; import com.l2jserver.model.world.capability.Attackable; import com.l2jserver.model.world.capability.Attacker; diff --git a/data/template/script/template/item/AdenaItemTemplate.java b/data/template/script/template/item/AdenaItemTemplate.java new file mode 100644 index 000000000..bf8307682 --- /dev/null +++ b/data/template/script/template/item/AdenaItemTemplate.java @@ -0,0 +1,12 @@ +package script.template.item; + +import com.l2jserver.model.id.TemplateID; +import com.l2jserver.model.template.ItemTemplate; + +public class AdenaItemTemplate extends ItemTemplate { + public static final TemplateID ID = new TemplateID(57); + + public AdenaItemTemplate() { + super(ID); + } +} diff --git a/data/template/com/l2jserver/model/template/item/TestPotionTemplate.java b/data/template/script/template/item/TestPotionTemplate.java similarity index 89% rename from data/template/com/l2jserver/model/template/item/TestPotionTemplate.java rename to data/template/script/template/item/TestPotionTemplate.java index 7c4760e22..37cf853c2 100644 --- a/data/template/com/l2jserver/model/template/item/TestPotionTemplate.java +++ b/data/template/script/template/item/TestPotionTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.item; +package script.template.item; import com.l2jserver.model.template.PotionTemplate; import com.l2jserver.model.world.capability.Attackable; diff --git a/data/template/com/l2jserver/model/template/skill/TestSkillTemplate.java b/data/template/script/template/skill/TestSkillTemplate.java similarity index 88% rename from data/template/com/l2jserver/model/template/skill/TestSkillTemplate.java rename to data/template/script/template/skill/TestSkillTemplate.java index 414846e0b..09f4e6bc7 100644 --- a/data/template/com/l2jserver/model/template/skill/TestSkillTemplate.java +++ b/data/template/script/template/skill/TestSkillTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.skill; +package script.template.skill; import com.l2jserver.model.template.SkillTemplate; import com.l2jserver.model.world.capability.Castable; diff --git a/data/template/com/l2jserver/model/template/weapon/TestWeaponTemplate.java b/data/template/script/template/weapon/TestWeaponTemplate.java similarity index 94% rename from data/template/com/l2jserver/model/template/weapon/TestWeaponTemplate.java rename to data/template/script/template/weapon/TestWeaponTemplate.java index a2c3f8115..00c1aea1f 100644 --- a/data/template/com/l2jserver/model/template/weapon/TestWeaponTemplate.java +++ b/data/template/script/template/weapon/TestWeaponTemplate.java @@ -1,4 +1,4 @@ -package com.l2jserver.model.template.weapon; +package script.template.weapon; import com.l2jserver.model.template.WeaponTemplate; import com.l2jserver.model.world.capability.Attackable; diff --git a/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java b/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java deleted file mode 100644 index f9ba28382..000000000 --- a/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.l2jserver.db.dao.db4o; - -import com.google.inject.Inject; -import com.l2jserver.service.database.AbstractDAO; -import com.l2jserver.service.database.DB4ODatabaseService; - -public class AbstractDB4ODAO extends AbstractDAO implements BD4ODAO { - protected final DB4ODatabaseService database; - - @Inject - protected AbstractDB4ODAO(DB4ODatabaseService database) { - super(database); - this.database = database; - } -} diff --git a/src/dao/db4o/com/l2jserver/db/dao/db4o/BD4ODAO.java b/src/dao/db4o/com/l2jserver/db/dao/db4o/BD4ODAO.java deleted file mode 100644 index 8967570ef..000000000 --- a/src/dao/db4o/com/l2jserver/db/dao/db4o/BD4ODAO.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.l2jserver.db.dao.db4o; - -public interface BD4ODAO { - -} diff --git a/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java b/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java deleted file mode 100644 index 90e6e5e08..000000000 --- a/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.l2jserver.db.dao.db4o; - -import java.util.List; - -import com.google.inject.Inject; -import com.l2jserver.db.dao.CharacterDAO; -import com.l2jserver.model.id.CharacterID; -import com.l2jserver.model.world.L2Character; -import com.l2jserver.service.database.DB4ODatabaseService; - -public class DB4OCharacterDAO extends AbstractDB4ODAO implements CharacterDAO { - @Inject - protected DB4OCharacterDAO(DB4ODatabaseService database) { - super(database); - } - - @Override - public L2Character load(CharacterID id) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean save(L2Character character) { - // TODO Auto-generated method stub - return false; - } - - @Override - public List listIDs() { - // TODO Auto-generated method stub - return null; - } -} diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java b/src/dao/mysql5/script/dao/mysql5/AbstractMySQL5DAO.java similarity index 92% rename from src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java rename to src/dao/mysql5/script/dao/mysql5/AbstractMySQL5DAO.java index a3cf638bc..45776430d 100644 --- a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java +++ b/src/dao/mysql5/script/dao/mysql5/AbstractMySQL5DAO.java @@ -1,4 +1,4 @@ -package com.l2jserver.db.dao.mysql5; +package script.dao.mysql5; import com.google.inject.Inject; import com.l2jserver.service.database.AbstractDAO; diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java b/src/dao/mysql5/script/dao/mysql5/DAOModuleMySQL5.java similarity index 91% rename from src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java rename to src/dao/mysql5/script/dao/mysql5/DAOModuleMySQL5.java index 5854d9d02..2b9e9d432 100644 --- a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java +++ b/src/dao/mysql5/script/dao/mysql5/DAOModuleMySQL5.java @@ -1,4 +1,4 @@ -package com.l2jserver.db.dao.mysql5; +package script.dao.mysql5; import com.google.inject.AbstractModule; import com.google.inject.Scopes; diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java b/src/dao/mysql5/script/dao/mysql5/MySQL5CharacterDAO.java similarity index 98% rename from src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java rename to src/dao/mysql5/script/dao/mysql5/MySQL5CharacterDAO.java index dc123a810..85890dd89 100644 --- a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java +++ b/src/dao/mysql5/script/dao/mysql5/MySQL5CharacterDAO.java @@ -1,4 +1,4 @@ -package com.l2jserver.db.dao.mysql5; +package script.dao.mysql5; import java.sql.PreparedStatement; import java.sql.ResultSet; diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java b/src/dao/mysql5/script/dao/mysql5/MySQL5ItemDAO.java similarity index 98% rename from src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java rename to src/dao/mysql5/script/dao/mysql5/MySQL5ItemDAO.java index ddc1aed1f..d4cf1ac68 100644 --- a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java +++ b/src/dao/mysql5/script/dao/mysql5/MySQL5ItemDAO.java @@ -1,4 +1,4 @@ -package com.l2jserver.db.dao.mysql5; +package script.dao.mysql5; import java.sql.PreparedStatement; import java.sql.ResultSet; diff --git a/src/main/java/com/l2jserver/GameServerModule.java b/src/main/java/com/l2jserver/GameServerModule.java index 5942292ea..7a9439c9c 100644 --- a/src/main/java/com/l2jserver/GameServerModule.java +++ b/src/main/java/com/l2jserver/GameServerModule.java @@ -1,7 +1,8 @@ package com.l2jserver; +import script.dao.mysql5.DAOModuleMySQL5; + import com.google.inject.AbstractModule; -import com.l2jserver.db.dao.mysql5.DAOModuleMySQL5; import com.l2jserver.model.id.factory.IDFactoryModule; import com.l2jserver.routines.GameServerInitializationRoutine; import com.l2jserver.service.BasicServiceModule; diff --git a/src/main/java/com/l2jserver/game/net/Lineage2PipelineFactory.java b/src/main/java/com/l2jserver/game/net/Lineage2PipelineFactory.java index 07cd03036..a9ff63340 100644 --- a/src/main/java/com/l2jserver/game/net/Lineage2PipelineFactory.java +++ b/src/main/java/com/l2jserver/game/net/Lineage2PipelineFactory.java @@ -9,14 +9,13 @@ import org.jboss.netty.logging.InternalLogLevel; import com.google.inject.Inject; import com.google.inject.Injector; -import com.l2jserver.game.net.codec.Lineage2FrameDecoder; import com.l2jserver.game.net.codec.Lineage2Decrypter; -import com.l2jserver.game.net.codec.Lineage2FrameEncoder; import com.l2jserver.game.net.codec.Lineage2Encrypter; +import com.l2jserver.game.net.codec.Lineage2FrameDecoder; +import com.l2jserver.game.net.codec.Lineage2FrameEncoder; import com.l2jserver.game.net.codec.Lineage2PacketReader; import com.l2jserver.game.net.codec.Lineage2PacketWriter; import com.l2jserver.game.net.handler.Lineage2PacketHandler; -import com.l2jserver.service.logging.LoggingService; public class Lineage2PipelineFactory implements ChannelPipelineFactory { private final Injector injector; @@ -32,15 +31,14 @@ public class Lineage2PipelineFactory implements ChannelPipelineFactory { pipeline.addLast("frame.encoder", new Lineage2FrameEncoder()); pipeline.addLast("frame.decoder", new Lineage2FrameDecoder()); - + pipeline.addLast(Lineage2Encrypter.HANDLER_NAME, new Lineage2Encrypter()); pipeline.addLast(Lineage2Decrypter.HANDLER_NAME, new Lineage2Decrypter()); pipeline.addLast("packet.writer", new Lineage2PacketWriter()); - pipeline.addLast("packet.reader", new Lineage2PacketReader(injector, - injector.getInstance(LoggingService.class))); + pipeline.addLast("packet.reader", new Lineage2PacketReader(injector)); pipeline.addLast("packet.handler", new Lineage2PacketHandler()); diff --git a/src/main/java/com/l2jserver/game/net/codec/Lineage2PacketReader.java b/src/main/java/com/l2jserver/game/net/codec/Lineage2PacketReader.java index c3809a2ff..c3d52159a 100644 --- a/src/main/java/com/l2jserver/game/net/codec/Lineage2PacketReader.java +++ b/src/main/java/com/l2jserver/game/net/codec/Lineage2PacketReader.java @@ -4,23 +4,23 @@ import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.inject.Inject; import com.google.inject.Injector; import com.l2jserver.game.net.packet.ClientPacket; import com.l2jserver.game.net.packet.client.AuthLoginPacket; import com.l2jserver.game.net.packet.client.ProtocolVersionPacket; -import com.l2jserver.service.logging.Logger; -import com.l2jserver.service.logging.LoggingService; public class Lineage2PacketReader extends OneToOneDecoder { private final Injector injector; - private final Logger logger; + private final Logger logger = LoggerFactory + .getLogger(Lineage2PacketReader.class); @Inject - public Lineage2PacketReader(Injector injector, LoggingService logging) { + public Lineage2PacketReader(Injector injector) { this.injector = injector; - this.logger = logging.getLogger(Lineage2PacketReader.class); } @Override diff --git a/src/main/java/com/l2jserver/game/net/packet/client/ProtocolVersionPacket.java b/src/main/java/com/l2jserver/game/net/packet/client/ProtocolVersionPacket.java index 3ff2ab2d5..d96d8589e 100644 --- a/src/main/java/com/l2jserver/game/net/packet/client/ProtocolVersionPacket.java +++ b/src/main/java/com/l2jserver/game/net/packet/client/ProtocolVersionPacket.java @@ -3,20 +3,20 @@ package com.l2jserver.game.net.packet.client; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.l2jserver.L2JConstants; import com.l2jserver.game.net.Lineage2Connection; import com.l2jserver.game.net.packet.AbstractClientPacket; import com.l2jserver.game.net.packet.server.KeyPacket; -import com.l2jserver.service.logging.Logger; -import com.l2jserver.service.logging.guice.InjectLogger; public class ProtocolVersionPacket extends AbstractClientPacket { public static final int OPCODE = 0x0e; // services - @InjectLogger - private final Logger logger = null; + private final Logger logger = LoggerFactory + .getLogger(ProtocolVersionPacket.class); // packet private long version; diff --git a/src/main/java/com/l2jserver/model/world/capability/Scriptable.java b/src/main/java/com/l2jserver/model/world/capability/Scriptable.java index 82e08e80f..a2bb70e32 100644 --- a/src/main/java/com/l2jserver/model/world/capability/Scriptable.java +++ b/src/main/java/com/l2jserver/model/world/capability/Scriptable.java @@ -1,7 +1,7 @@ package com.l2jserver.model.world.capability; import com.l2jserver.model.world.AbstractObject; -import com.l2jserver.service.game.script.Script; +import com.l2jserver.service.game.scripting.Script; /** * Defines an {@link AbstractObject} that can be controller by an {@link Script} diff --git a/src/main/java/com/l2jserver/service/compiler/CompilerService.java b/src/main/java/com/l2jserver/service/compiler/CompilerService.java deleted file mode 100644 index 905aa949b..000000000 --- a/src/main/java/com/l2jserver/service/compiler/CompilerService.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.l2jserver.service.compiler; - -import com.l2jserver.service.Service; - -public interface CompilerService extends Service { - Class compile(byte[] clazz); - ClassLoader getClassLoader(); -} diff --git a/src/main/java/com/l2jserver/service/compiler/DynamicClassLoader.java b/src/main/java/com/l2jserver/service/compiler/DynamicClassLoader.java deleted file mode 100644 index f71266d00..000000000 --- a/src/main/java/com/l2jserver/service/compiler/DynamicClassLoader.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.l2jserver.service.compiler; - -public class DynamicClassLoader extends ClassLoader { - public DynamicClassLoader() { - super(); - } - - public DynamicClassLoader(ClassLoader parent) { - super(parent); - } -} diff --git a/src/main/java/com/l2jserver/service/compiler/JavacCompilerService.java b/src/main/java/com/l2jserver/service/compiler/JavacCompilerService.java deleted file mode 100644 index 88f1e62cf..000000000 --- a/src/main/java/com/l2jserver/service/compiler/JavacCompilerService.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.l2jserver.service.compiler; - -import com.l2jserver.service.ServiceStartException; -import com.l2jserver.service.ServiceStopException; - -public class JavacCompilerService implements CompilerService { - @Override - public void start() throws ServiceStartException { - // TODO Auto-generated method stub - - } - - @Override - public Class compile(byte[] clazz) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ClassLoader getClassLoader() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void stop() throws ServiceStopException { - - } -} diff --git a/src/main/java/com/l2jserver/service/game/script/ScriptingService.java b/src/main/java/com/l2jserver/service/game/script/ScriptingService.java deleted file mode 100644 index b0b8ee957..000000000 --- a/src/main/java/com/l2jserver/service/game/script/ScriptingService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.l2jserver.service.game.script; - -import com.l2jserver.service.Service; - -public interface ScriptingService extends Service { - -} diff --git a/src/main/java/com/l2jserver/service/game/scripting/CompilationResult.java b/src/main/java/com/l2jserver/service/game/scripting/CompilationResult.java new file mode 100644 index 000000000..3435bb903 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/CompilationResult.java @@ -0,0 +1,68 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting; + +/** + * This class represents compilation result of script context + * + * @author Rogiel + */ +public class CompilationResult { + /** + * List of classes that were compiled by compiler + */ + private final Class[] compiledClasses; + + /** + * Classloader that was used to load classes + */ + private final ScriptClassLoader classLoader; + + /** + * Creates new instance of CompilationResult with classes that has to be + * parsed and classloader that was used to load classes + * + * @param compiledClasses + * classes compiled by compiler + * @param classLoader + * classloader that was used by compiler + */ + public CompilationResult(Class[] compiledClasses, + ScriptClassLoader classLoader) { + this.compiledClasses = compiledClasses; + this.classLoader = classLoader; + } + + /** + * Returns classLoader that was used by compiler + * + * @return classloader that was used by compiler + */ + public ScriptClassLoader getClassLoader() { + return classLoader; + } + + /** + * Retunrs list of classes that were compiled + * + * @return list of classes that were compiled + */ + public Class[] getCompiledClasses() { + return compiledClasses; + } +} diff --git a/src/main/java/com/l2jserver/service/game/script/Script.java b/src/main/java/com/l2jserver/service/game/scripting/Script.java similarity index 84% rename from src/main/java/com/l2jserver/service/game/script/Script.java rename to src/main/java/com/l2jserver/service/game/scripting/Script.java index 34cde54fc..44fcf67bb 100644 --- a/src/main/java/com/l2jserver/service/game/script/Script.java +++ b/src/main/java/com/l2jserver/service/game/scripting/Script.java @@ -1,4 +1,4 @@ -package com.l2jserver.service.game.script; +package com.l2jserver.service.game.scripting; import com.l2jserver.model.world.capability.Scriptable; @@ -11,6 +11,6 @@ public interface Script extends Runnable { void load(O object); void unload(); - + O getObject(); } diff --git a/src/main/java/com/l2jserver/service/game/scripting/ScriptClassLoader.java b/src/main/java/com/l2jserver/service/game/scripting/ScriptClassLoader.java new file mode 100644 index 000000000..0414332d1 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/ScriptClassLoader.java @@ -0,0 +1,96 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.Set; + +/** + * + * Abstract class loader that should be extended by child classloaders. If + * needed, this class should wrap another classloader. + * + * @author Rogiel + */ +public abstract class ScriptClassLoader extends URLClassLoader { + + /** + * Just for compatibility with {@link URLClassLoader} + * + * @param urls + * list of urls + * @param parent + * parent classloader + */ + public ScriptClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + /** + * Just for compatibility with {@link URLClassLoader} + * + * @param urls + * list of urls + */ + public ScriptClassLoader(URL[] urls) { + super(urls); + } + + /** + * Just for compatibility with {@link URLClassLoader} + * + * @param urls + * list of urls + * @param parent + * parent classloader + * @param factory + * {@link java.net.URLStreamHandlerFactory} + */ + public ScriptClassLoader(URL[] urls, ClassLoader parent, + URLStreamHandlerFactory factory) { + super(urls, parent, factory); + } + + /** + * Adds library to this classloader, it shuould be jar file + * + * @param file + * jar file + * @throws IOException + * if can't add library + */ + public abstract void addLibrary(File file) throws IOException; + + /** + * Returns unmodifiable set of class names that were loaded from libraries + * + * @return unmodifiable set of class names that were loaded from libraries + */ + public abstract Set getLibraryClasses(); + + /** + * Retuns unmodifiable set of class names that were compiled + * + * @return unmodifiable set of class names that were compiled + */ + public abstract Set getCompiledClasses(); +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/ScriptCompiler.java b/src/main/java/com/l2jserver/service/game/scripting/ScriptCompiler.java new file mode 100644 index 000000000..5f74afb57 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/ScriptCompiler.java @@ -0,0 +1,90 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting; + +import java.io.File; + +/** + * This interface reperesents common functionality list that should be available + * for any commpiler that is going to be used with scripting engine. For + * instance, groovy can be used, hoever it produces by far not the best bytecode + * so by default javac from sun is used. + * + * @author Rogiel + */ +public interface ScriptCompiler { + /** + * Sets parent class loader for this compiler.
+ *
+ * Warning, for now only + * + * @param classLoader + * ScriptClassLoader that will be used as parent + */ + void setParentClassLoader(ScriptClassLoader classLoader); + + /** + * List of jar files that are required for compilation + * + * @param files + * list of jar files + */ + void setLibraires(Iterable files); + + /** + * Compiles single class that is represented as string + * + * @param className + * class name + * @param sourceCode + * class sourse code + * @return {@link CompilationResult} + */ + CompilationResult compile(String className, String sourceCode); + + /** + * Compiles classes that are represented as strings + * + * @param className + * class names + * @param sourceCode + * class sources + * @return {@link CompilationResult} + * @throws IllegalArgumentException + * if number of class names != number of sources + */ + CompilationResult compile(String[] className, String[] sourceCode) + throws IllegalArgumentException; + + /** + * Compiles list of files + * + * @param compilationUnits + * list of files + * @return {@link CompilationResult} + */ + CompilationResult compile(Iterable compilationUnits); + + /** + * Returns array of supported file types. This files will be threated as + * source files. + * + * @return array of supported file types. + */ + String[] getSupportedFileTypes(); +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/ScriptContext.java b/src/main/java/com/l2jserver/service/game/scripting/ScriptContext.java new file mode 100644 index 000000000..66669d87e --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/ScriptContext.java @@ -0,0 +1,181 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting; + +import java.io.File; +import java.util.Collection; + +import com.l2jserver.service.game.scripting.classlistener.ClassListener; +import com.l2jserver.service.game.scripting.classlistener.DefaultClassListener; +import com.l2jserver.service.game.scripting.metadata.OnClassLoad; +import com.l2jserver.service.game.scripting.metadata.OnClassUnload; + +/** + * This class represents script context that can be loaded, unloaded, etc...
+ * + * @author Rogiel + */ +public interface ScriptContext { + /** + * Initializes script context. Calls the compilation task.
+ * After compilation static methods marked with {@link OnClassLoad} are + * invoked + */ + void init(); + + /** + * Notifies all script classes that they must save their data and release + * resources to prevent memory leaks. It's done via static methods with + * {@link OnClassUnload} annotation + */ + void shutdown(); + + /** + * Invokes {@link #shutdown()}, after that invokes {@link #init()}. Root + * folder remains the same, but new compiler and classloader are used. + */ + void reload(); + + /** + * Returns the root directory for script engine. Only one script engine per + * root directory is allowed. + * + * @return root directory for script engine + */ + File getRoot(); + + /** + * Returns compilation result of this script context + * + * @return compilation result + */ + CompilationResult getCompilationResult(); + + /** + * Returns true if this script context is loaded + * + * @return true if context is initialized + */ + boolean isInitialized(); + + /** + * Sets files that represents jar files, they will be used as libraries + * + * @param files + * that points to jar file, will be used as libraries + */ + void setLibraries(Iterable files); + + /** + * Returns list of files that are used as libraries for this script context + * + * @return list of libraries + */ + Iterable getLibraries(); + + /** + * Returns parent script context of this context. Returns null if none. + * + * @return parent Script context of this context or null + */ + ScriptContext getParentScriptContext(); + + /** + * Returns list of child contexts or null if no contextes present + * + * @return list of child contexts or null + */ + Collection getChildScriptContexts(); + + /** + * Adds child contexts to this context. If this context is initialized - + * chiled context will be initialized immideatly. In other case child + * context will be just added and initialized when {@link #init()} would be + * called. Duplicated child contexts are not allowed, in such case child + * will be ignored + * + * @param context + * child context + */ + void addChildScriptContext(ScriptContext context); + + /** + * Sets the class listener for this script context. + * + * @param cl + * class listener + */ + void setClassListener(ClassListener cl); + + /** + * Returns class listener associated with this ScriptContext.
+ * If it's null - returns parent classListener.
+ * If parent is null and classListener is null - it will set + * {@link DefaultClassListener} as class listener and return it + * + * @return Associated class listener + */ + ClassListener getClassListener(); + + /** + * Sets compiler class name for this script context.
+ * Compiler is not inherrited by children.
+ * + * @param className + * compiler class name + */ + void setCompilerClassName(String className); + + /** + * Returns compiler class name that will be used for this script context. + * + * @return compiler class name that will be used for tis script context + */ + String getCompilerClassName(); + + /** + * Tests if this ScriptContext is equal to another ScriptContext. + * Comparation is done by comparing root files and parent contexts (if there + * is any parent) + * + * @param obj + * object to compare with + * @return result of comparation + */ + @Override + boolean equals(Object obj); + + /** + * Returns hashCoded of this ScriptContext. Hashcode is calculated using + * root file and parent context(if available) + * + * @return hashcode + */ + @Override + int hashCode(); + + /** + * This method overrides finalization to ensure that active script context + * will not be collected by GC. If such situation happens - + * {@link #shutdown()} is called to ensure that resources were released. + * + * @throws Throwable + * if something goes wrong during finalization + */ + void finalize() throws Throwable; +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/ScriptContextFactory.java b/src/main/java/com/l2jserver/service/game/scripting/ScriptContextFactory.java new file mode 100644 index 000000000..925271ebd --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/ScriptContextFactory.java @@ -0,0 +1,42 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting; + +import java.io.File; + +import com.l2jserver.service.game.scripting.impl.ScriptContextImpl; + +/** + * This class is script context provider. We can switch to any other + * ScriptContext implementation later, so it's good to have factory class + * + * @author Rogiel + */ +public final class ScriptContextFactory { + public static ScriptContext getScriptContext(File root, ScriptContext parent) + throws InstantiationException { + ScriptContextImpl ctx; + if (parent == null) { + ctx = new ScriptContextImpl(root); + } else { + ctx = new ScriptContextImpl(root, parent); + parent.addChildScriptContext(ctx); + } + return ctx; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/ScriptingService.java b/src/main/java/com/l2jserver/service/game/scripting/ScriptingService.java new file mode 100644 index 000000000..59ecd6706 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/ScriptingService.java @@ -0,0 +1,22 @@ +package com.l2jserver.service.game.scripting; + +import java.io.File; + +import com.l2jserver.service.Service; + +public interface ScriptingService extends Service { + /** + * Creates script context, sets the root context. Adds child context if + * needed + * + * @param root + * file that will be threated as root for compiler + * @param parent + * parent of new ScriptContext + * @return ScriptContext with presetted root file + * @throws InstantiationException + * if java compiler is not aviable + */ + ScriptContext getScriptContext(File root, ScriptContext parent) + throws InstantiationException; +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/ScriptingServiceImpl.java b/src/main/java/com/l2jserver/service/game/scripting/ScriptingServiceImpl.java new file mode 100644 index 000000000..9643b73a8 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/ScriptingServiceImpl.java @@ -0,0 +1,32 @@ +package com.l2jserver.service.game.scripting; + +import java.io.File; + +import com.l2jserver.service.ServiceStartException; +import com.l2jserver.service.ServiceStopException; +import com.l2jserver.service.game.scripting.impl.ScriptContextImpl; + +public class ScriptingServiceImpl implements ScriptingService { + @Override + public void start() throws ServiceStartException { + + } + + @Override + public ScriptContext getScriptContext(File root, ScriptContext parent) + throws InstantiationException { + ScriptContextImpl ctx; + if (parent == null) { + ctx = new ScriptContextImpl(root); + } else { + ctx = new ScriptContextImpl(root, parent); + parent.addChildScriptContext(ctx); + } + return ctx; + } + + @Override + public void stop() throws ServiceStopException { + + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/classlistener/ClassListener.java b/src/main/java/com/l2jserver/service/game/scripting/classlistener/ClassListener.java new file mode 100644 index 000000000..2bd35dcc6 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/classlistener/ClassListener.java @@ -0,0 +1,46 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.classlistener; + +/** + * This interface implements listener that is called post class load/before + * class unload.
+ * Default implementation is: {@link DefaultClassListener} + * + * @author Rogiel + */ +public interface ClassListener { + + /** + * This method is invoked after classes were loaded. As areguments are + * passes all loaded classes + * + * @param classes + * classes that were loaded + */ + public void postLoad(Class... classes); + + /** + * This method is invoked before class unloading. As argument are passes all + * loaded classes + * + * @param classes + * classes that were loaded + */ + public void preUnload(Class... classes); +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/classlistener/DefaultClassListener.java b/src/main/java/com/l2jserver/service/game/scripting/classlistener/DefaultClassListener.java new file mode 100644 index 000000000..792b4f6ee --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/classlistener/DefaultClassListener.java @@ -0,0 +1,88 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.classlistener; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.l2jserver.service.game.scripting.metadata.OnClassLoad; +import com.l2jserver.service.game.scripting.metadata.OnClassUnload; + +/** + * @author Rogiel + */ +public class DefaultClassListener implements ClassListener { + + private static final Logger log = LoggerFactory + .getLogger(DefaultClassListener.class); + + @Override + public void postLoad(Class... classes) { + for (Class c : classes) { + doMethodInvoke(c.getDeclaredMethods(), OnClassLoad.class); + } + } + + @Override + public void preUnload(Class... classes) { + for (Class c : classes) { + doMethodInvoke(c.getDeclaredMethods(), OnClassUnload.class); + } + } + + /** + * Actually invokes method where given annotation class is present. Only + * static methods can be invoked + * + * @param methods + * Methods to scan for annotations + * @param annotationClass + * class of annotation to search for + */ + static void doMethodInvoke(Method[] methods, + Class annotationClass) { + for (Method m : methods) { + + if (!Modifier.isStatic(m.getModifiers())) { + continue; + } + + boolean accessible = m.isAccessible(); + m.setAccessible(true); + + if (m.getAnnotation(annotationClass) != null) { + try { + m.invoke(null); + } catch (IllegalAccessException e) { + log.error("Can't access method " + m.getName() + + " of class " + m.getDeclaringClass().getName(), e); + } catch (InvocationTargetException e) { + log.error("Can't invoke method " + m.getName() + + " of class " + m.getDeclaringClass().getName(), e); + } + } + + m.setAccessible(accessible); + } + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/ScriptContextImpl.java b/src/main/java/com/l2jserver/service/game/scripting/impl/ScriptContextImpl.java new file mode 100644 index 000000000..b501b9e8f --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/ScriptContextImpl.java @@ -0,0 +1,337 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl; + +import java.io.File; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.l2jserver.service.game.scripting.CompilationResult; +import com.l2jserver.service.game.scripting.ScriptCompiler; +import com.l2jserver.service.game.scripting.ScriptContext; +import com.l2jserver.service.game.scripting.classlistener.ClassListener; +import com.l2jserver.service.game.scripting.classlistener.DefaultClassListener; + +/** + * This class is actual implementation of {@link ScriptContext} + * + * @author Rogiel + */ +public class ScriptContextImpl implements ScriptContext { + /** + * logger for this class + */ + private static final Logger log = LoggerFactory + .getLogger(ScriptContextImpl.class); + + /** + * Script context that is parent for this script context + */ + private final ScriptContext parentScriptContext; + + /** + * Libraries (list of jar files) that have to be loaded class loader + */ + private Iterable libraries; + + /** + * Root directory of this script context. It and it's subdirectories will be + * scanned for .java files. + */ + private final File root; + + /** + * Result of compilation of script context + */ + private CompilationResult compilationResult; + + /** + * List of child script contexts + */ + private Set childScriptContexts; + + /** + * Classlistener for this script context + */ + private ClassListener classListener; + + /** + * Class name of the compiler that will be used to compile sources + */ + private String compilerClassName; + + /** + * Creates new scriptcontext with given root file + * + * @param root + * file that represents root directory of this script context + * @throws NullPointerException + * if root is null + * @throws IllegalArgumentException + * if root directory doesn't exists or is not a directory + */ + public ScriptContextImpl(File root) { + this(root, null); + } + + /** + * Creates new ScriptContext with given file as root and another + * ScriptContext as parent + * + * @param root + * file that represents root directory of this script context + * @param parent + * parent ScriptContex. It's classes and libraries will be + * accessible for this script context + * @throws NullPointerException + * if root is null + * @throws IllegalArgumentException + * if root directory doesn't exists or is not a directory + */ + public ScriptContextImpl(File root, ScriptContext parent) { + if (root == null) { + throw new NullPointerException("Root file must be specified"); + } + + if (!root.exists() || !root.isDirectory()) { + throw new IllegalArgumentException( + "Root directory not exists or is not a directory"); + } + + this.root = root; + this.parentScriptContext = parent; + } + + @Override + public synchronized void init() { + + if (compilationResult != null) { + log.error("", new Exception( + "Init request on initialized ScriptContext")); + return; + } + + ScriptCompiler scriptCompiler = instantiateCompiler(); + + @SuppressWarnings("unchecked") + Collection files = FileUtils.listFiles(root, + scriptCompiler.getSupportedFileTypes(), true); + + if (parentScriptContext != null) { + scriptCompiler.setParentClassLoader(parentScriptContext + .getCompilationResult().getClassLoader()); + } + + scriptCompiler.setLibraires(libraries); + compilationResult = scriptCompiler.compile(files); + + getClassListener().postLoad(compilationResult.getCompiledClasses()); + + if (childScriptContexts != null) { + for (ScriptContext context : childScriptContexts) { + context.init(); + } + } + } + + @Override + public synchronized void shutdown() { + + if (compilationResult == null) { + log.error("Shutdown of not initialized stript context", + new Exception()); + return; + } + + if (childScriptContexts != null) { + for (ScriptContext child : childScriptContexts) { + child.shutdown(); + } + } + + getClassListener().preUnload(compilationResult.getCompiledClasses()); + compilationResult = null; + } + + @Override + public void reload() { + shutdown(); + init(); + } + + @Override + public File getRoot() { + return root; + } + + @Override + public CompilationResult getCompilationResult() { + return compilationResult; + } + + @Override + public synchronized boolean isInitialized() { + return compilationResult != null; + } + + @Override + public void setLibraries(Iterable files) { + this.libraries = files; + } + + @Override + public Iterable getLibraries() { + return libraries; + } + + @Override + public ScriptContext getParentScriptContext() { + return parentScriptContext; + } + + @Override + public Collection getChildScriptContexts() { + return childScriptContexts; + } + + /** + * {@inheritDoc} + */ + @Override + public void addChildScriptContext(ScriptContext context) { + synchronized (this) { + if (childScriptContexts == null) { + childScriptContexts = new HashSet(); + } + + if (childScriptContexts.contains(context)) { + log.error("Double child definition, root: " + + root.getAbsolutePath() + ", child: " + + context.getRoot().getAbsolutePath()); + return; + } + + if (isInitialized()) { + context.init(); + } + } + childScriptContexts.add(context); + } + + @Override + public void setClassListener(ClassListener cl) { + classListener = cl; + } + + @Override + public ClassListener getClassListener() { + if (classListener == null) { + if (getParentScriptContext() == null) { + setClassListener(new DefaultClassListener()); + return classListener; + } else { + return getParentScriptContext().getClassListener(); + } + } else { + return classListener; + } + } + + @Override + public void setCompilerClassName(String className) { + this.compilerClassName = className; + } + + @Override + public String getCompilerClassName() { + return this.compilerClassName; + } + + /** + * Creates new instance of ScriptCompiler that should be used with this + * ScriptContext + * + * @return instance of ScriptCompiler + * @throws RuntimeException + * if failed to create instance + */ + protected ScriptCompiler instantiateCompiler() throws RuntimeException { + ClassLoader cl = getClass().getClassLoader(); + if (getParentScriptContext() != null) { + cl = getParentScriptContext().getCompilationResult() + .getClassLoader(); + } + + ScriptCompiler sc; + try { + sc = (ScriptCompiler) Class.forName(getCompilerClassName(), true, + cl).newInstance(); + } catch (Exception e) { + RuntimeException e1 = new RuntimeException( + "Can't create instance of compiler", e); + log.error("Compiler exception", e1); + throw e1; + } + + return sc; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ScriptContextImpl)) { + return false; + } + + ScriptContextImpl another = (ScriptContextImpl) obj; + + if (parentScriptContext == null) { + return another.getRoot().equals(root); + } else { + return another.getRoot().equals(root) + && parentScriptContext.equals(another.parentScriptContext); + } + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = parentScriptContext != null ? parentScriptContext + .hashCode() : 0; + result = 31 * result + root.hashCode(); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void finalize() throws Throwable { + if (compilationResult != null) { + log.error("Finalization of initialized ScriptContext. Forcing context shutdown."); + shutdown(); + } + super.finalize(); + } +} \ No newline at end of file diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/BinaryClass.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/BinaryClass.java new file mode 100644 index 000000000..d9f8a03b5 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/BinaryClass.java @@ -0,0 +1,212 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.URI; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.JavaFileObject; + +/** + * This class is just a hack to make javac compiler work with classes loaded by + * prevoius classloader. Also it's used as container for loaded class + * + * @author Rogiel + */ +public class BinaryClass implements JavaFileObject { + /** + * ClassName + */ + private final String name; + + /** + * Class data will be written here + */ + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + /** + * Locaded class will be set here + */ + private Class definedClass; + + /** + * Constructor that accepts class name as parameter + * + * @param name + * class name + */ + protected BinaryClass(String name) { + this.name = name; + } + + /** + * Throws {@link UnsupportedOperationException} + * + * @return nothing + */ + @Override + public URI toUri() { + throw new UnsupportedOperationException(); + } + + /** + * Returns name of this class with ".class" suffix + * + * @return name of this class with ".class" suffix + */ + @Override + public String getName() { + return name + ".class"; + } + + /** + * Creates new ByteArrayInputStream, it just wraps class binary data + * + * @return input stream for class data + * @throws IOException + * never thrown + */ + @Override + public InputStream openInputStream() throws IOException { + return new ByteArrayInputStream(baos.toByteArray()); + } + + /** + * Opens ByteArrayOutputStream for class data + * + * @return output stream + * @throws IOException + * never thrown + */ + @Override + public OutputStream openOutputStream() throws IOException { + return baos; + } + + /** + * Throws {@link UnsupportedOperationException} + * + * @return nothing + */ + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) + throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * Throws {@link UnsupportedOperationException} + * + * @return nothing + */ + @Override + public Writer openWriter() throws IOException { + throw new UnsupportedOperationException(); + } + + /** + * Unsupported operation, always reutrns 0 + * + * @return 0 + */ + @Override + public long getLastModified() { + return 0; + } + + /** + * Unsupported operation, returns false + * + * @return false + */ + @Override + public boolean delete() { + return false; + } + + /** + * Returns true if {@link javax.tools.JavaFileObject.Kind#CLASS} + * + * @param simpleName + * doesn't matter + * @param kind + * kind to compare + * @return true if Kind is {@link javax.tools.JavaFileObject.Kind#CLASS} + */ + @Override + public boolean isNameCompatible(String simpleName, Kind kind) { + return Kind.CLASS.equals(kind); + } + + /** + * Returns bytes of class + * + * @return bytes of class + */ + public byte[] getBytes() { + return baos.toByteArray(); + } + + /** + * Returns class that was loaded from binary data of this object + * + * @return loaded class + */ + public Class getDefinedClass() { + return definedClass; + } + + /** + * Sets class that was loaded by this object + * + * @param definedClass + * class that was loaded + */ + public void setDefinedClass(Class definedClass) { + this.definedClass = definedClass; + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + return new InputStreamReader(new ByteArrayInputStream(getBytes())); + } + + @Override + public Modifier getAccessLevel() { + return Modifier.PUBLIC; + } + + @Override + public Kind getKind() { + return Kind.CLASS; + } + + @Override + public NestingKind getNestingKind() { + return null; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ClassFileManager.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ClassFileManager.java new file mode 100644 index 000000000..1d57bdd82 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ClassFileManager.java @@ -0,0 +1,208 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.tools.DiagnosticListener; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardLocation; + +import com.l2jserver.service.game.scripting.ScriptClassLoader; +import com.l2jserver.util.factory.CollectionFactory; + +/** + * This class extends manages loaded classes. It is also responsible for + * tricking compiler. Unfortunally compiler doen't work with classloaders, so we + * have to pass class data manually for each compilation. + * + * @author Rogiel + */ +public class ClassFileManager extends + ForwardingJavaFileManager { + + /** + * This map contains classes compiled for this classloader + */ + private final Map compiledClasses = CollectionFactory + .newMap(String.class, BinaryClass.class); + + /** + * Classloader that will be used to load compiled classes + */ + protected ScriptClassLoaderImpl loader; + + /** + * Parent classloader for loader + */ + protected ScriptClassLoader parentClassLoader; + + /** + * Creates new ClassFileManager. + * + * @param compiler + * that will be used + * @param listener + * class that will report compilation errors + */ + public ClassFileManager(JavaCompiler compiler, + DiagnosticListener listener) { + super(compiler.getStandardFileManager(listener, null, null)); + } + + /** + * Returns JavaFileObject that will be used to write class data into it by + * compiler + * + * @param location + * not used + * @param className + * JavaFileObject will have this className + * @param kind + * not used + * @param sibling + * not used + * @return JavaFileObject that will be uesd to store compiled class data + * @throws IOException + * never thrown + */ + @Override + public JavaFileObject getJavaFileForOutput(Location location, + String className, Kind kind, FileObject sibling) throws IOException { + BinaryClass co = new BinaryClass(className); + compiledClasses.put(className, co); + return co; + } + + /** + * Returns classloaded of this ClassFileManager. If not exists, creates new + * + * @param location + * not used + * @return classLoader of this ClassFileManager + */ + @Override + public synchronized ScriptClassLoaderImpl getClassLoader(Location location) { + if (loader == null) { + if (parentClassLoader != null) { + loader = new ScriptClassLoaderImpl(this, parentClassLoader); + } else { + loader = new ScriptClassLoaderImpl(this); + } + } + return loader; + } + + /** + * Sets paraentClassLoader for this classLoader + * + * @param classLoader + * parent class loader + */ + public void setParentClassLoader(ScriptClassLoader classLoader) { + this.parentClassLoader = classLoader; + } + + /** + * Adds library file. Library file must be a .jar archieve + * + * @param file + * link to jar archieve + * @throws IOException + * if something goes wrong + */ + public void addLibrary(File file) throws IOException { + ScriptClassLoaderImpl classLoader = getClassLoader(null); + classLoader.addLibrary(file); + } + + /** + * Adds list of files as libraries. Files must be jar archieves + * + * @param files + * list of jar archives + * @throws IOException + * if some5thing goes wrong + */ + public void addLibraries(Iterable files) throws IOException { + for (File f : files) { + addLibrary(f); + } + } + + /** + * Returns list of classes that were compiled by conpiler related to this + * ClassFileManager + * + * @return list of classes + */ + public Map getCompiledClasses() { + return compiledClasses; + } + + /** + * This method overrides class resolving procedure for compiler. It uses + * classloaders to resolve classes that compiler may need during + * compilation. + * + * Compiler by itself can't detect them. So we have to use this hack here. + * + * Hack is used only if compiler requests for classes in classpath. + * + * @param location + * Location to search classes + * @param packageName + * package to scan for classes + * @param kinds + * FileTypes to search + * @param recurse + * not used + * @return list of requered files + * @throws IOException + * if something foes wrong + */ + @Override + public Iterable list(Location location, String packageName, + Set kinds, boolean recurse) throws IOException { + Iterable objects = super.list(location, packageName, + kinds, recurse); + + if (StandardLocation.CLASS_PATH.equals(location) + && kinds.contains(Kind.CLASS)) { + List temp = new ArrayList(); + for (JavaFileObject object : objects) { + temp.add(object); + } + + temp.addAll(loader.getClassesForPackage(packageName)); + objects = temp; + } + + return objects; + } +} \ No newline at end of file diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ErrorListener.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ErrorListener.java new file mode 100644 index 000000000..8432599c5 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ErrorListener.java @@ -0,0 +1,64 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.util.Locale; + +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is simple compiler error listener that forwards errors to log4j + * logger + * + * @author Rogiel + */ +public class ErrorListener implements DiagnosticListener { + + /** + * Logger for this class + */ + private static final Logger log = LoggerFactory + .getLogger(ErrorListener.class); + + /** + * Reports compilation errors to log4j + * + * @param diagnostic + * compiler errors + */ + @Override + public void report(Diagnostic diagnostic) { + StringBuffer buffer = new StringBuffer(); + buffer.append("Compier Error Report Start").append("\n"); + buffer.append("errcode:").append(diagnostic.getCode()).append("\n"); + buffer.append("line :").append(diagnostic.getLineNumber()) + .append("\n"); + buffer.append("column :").append(diagnostic.getColumnNumber()) + .append("\n"); + buffer.append("message:") + .append(diagnostic.getMessage(Locale.getDefault())) + .append("\n"); + buffer.append("Compier Error Report End"); + log.error(buffer.toString()); + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/JavaSourceFromFile.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/JavaSourceFromFile.java new file mode 100644 index 000000000..0cb8bdf8e --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/JavaSourceFromFile.java @@ -0,0 +1,61 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.File; +import java.io.IOException; + +import javax.tools.SimpleJavaFileObject; + +import org.apache.commons.io.FileUtils; + +/** + * This class is simple wrapper for SimpleJavaFileObject that load class source + * from file sytem + * + * @author Rogiel + */ +public class JavaSourceFromFile extends SimpleJavaFileObject { + + /** + * Construct a JavaFileObject of the given kind and with the given File. + * + * @param file + * the file with source of this file object + * @param kind + * the kind of this file object + */ + public JavaSourceFromFile(File file, Kind kind) { + super(file.toURI(), kind); + } + + /** + * Returns class source represented as string. + * + * @param ignoreEncodingErrors + * not used + * @return class source + * @throws IOException + * if something goes wrong + */ + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) + throws IOException { + return FileUtils.readFileToString(new File(this.toUri())); + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/JavaSourceFromString.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/JavaSourceFromString.java new file mode 100644 index 000000000..cbb31a3ff --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/JavaSourceFromString.java @@ -0,0 +1,62 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.net.URI; + +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; + +/** + * This class allows us to compile sources that are located only in memory. + * + * @author Rogiel + */ +public class JavaSourceFromString extends SimpleJavaFileObject { + /** + * Source code of the class + */ + private final String code; + + /** + * Creates new object that contains sources of java class + * + * @param className + * class name of class + * @param code + * source code of class + */ + public JavaSourceFromString(String className, String code) { + super(URI.create("string:///" + className.replace('.', '/') + + JavaFileObject.Kind.SOURCE.extension), + JavaFileObject.Kind.SOURCE); + this.code = code; + } + + /** + * Returns class source code + * + * @param ignoreEncodingErrors + * not used + * @return class source code + */ + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ScriptClassLoaderImpl.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ScriptClassLoaderImpl.java new file mode 100644 index 000000000..d7ba81a58 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ScriptClassLoaderImpl.java @@ -0,0 +1,289 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import javax.tools.JavaFileObject; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.l2jserver.service.game.scripting.ScriptClassLoader; +import com.l2jserver.util.ClassUtils; + +/** + * This classloader is used to load script classes.
+ *
+ * Due to JavaCompiler limitations we have to keep list of available classes + * here. + * + * @author Rogiel + */ +public class ScriptClassLoaderImpl extends ScriptClassLoader { + + /** + * Logger + */ + private static final Logger log = LoggerFactory + .getLogger(ScriptClassLoaderImpl.class); + + /** + * URL Stream handler to allow valid url generation by + * {@link #getResource(String)} + */ + private final VirtualClassURLStreamHandler urlStreamHandler = new VirtualClassURLStreamHandler( + this); + + /** + * ClassFileManager that is related to this ClassLoader + */ + private final ClassFileManager classFileManager; + + /** + * Classes that were loaded from libraries. They are no parsed for any + * annotations, but they are needed by JavaCompiler to perform valid + * compilation + */ + private Set libraryClasses = new HashSet(); + + /** + * Creates new ScriptClassLoader with given ClassFileManger + * + * @param classFileManager + * classFileManager of this classLoader + */ + ScriptClassLoaderImpl(ClassFileManager classFileManager) { + super(new URL[] {}); + this.classFileManager = classFileManager; + } + + /** + * Creates new ScriptClassLoader with given ClassFileManger and another + * classLoader as parent + * + * @param classFileManager + * classFileManager of this classLoader + * @param parent + * parent classLoader + */ + ScriptClassLoaderImpl(ClassFileManager classFileManager, ClassLoader parent) { + super(new URL[] {}, parent); + this.classFileManager = classFileManager; + } + + /** + * Returns ClassFileManager that is related to this ClassLoader + * + * @return classFileManager of this classLoader + */ + public ClassFileManager getClassFileManager() { + return classFileManager; + } + + /** + * AddsLibrary jar + * + * @param file + * jar file to add + * @throws IOException + */ + @Override + public void addLibrary(File file) throws IOException { + URL fileURL = file.toURI().toURL(); + addURL(fileURL); + + JarFile jarFile = new JarFile(file); + + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + + String name = entry.getName(); + if (name.endsWith(".class")) { + name = name.substring(0, name.length() - 6); + name = name.replace('/', '.'); + libraryClasses.add(name); + } + } + + jarFile.close(); + } + + /** + * Loads class from library, parent or compiled + * + * @param name + * class to load + * @return loaded class + * @throws ClassNotFoundException + * if class not found + */ + @Override + public Class loadClass(String name) throws ClassNotFoundException { + BinaryClass bc = classFileManager.getCompiledClasses().get(name); + if (bc == null) { + return super.loadClass(name, true); + } + + Class c = bc.getDefinedClass(); + if (c == null) { + byte[] b = bc.getBytes(); + c = super.defineClass(name, b, 0, b.length); + bc.setDefinedClass(c); + } + return c; + } + + /** + * {@inheritDoc} + */ + @Override + public URL getResource(String name) { + + if (!name.endsWith(".class")) { + return super.getResource(name); + } else { + String newName = name.substring(0, name.length() - 6); + newName = newName.replace('/', '.'); + if (classFileManager.getCompiledClasses().containsKey(newName)) { + try { + return new URL(null, + VirtualClassURLStreamHandler.HANDLER_PROTOCOL + + newName, urlStreamHandler); + } catch (MalformedURLException e) { + log.error("Can't create url for compiled class", e); + } + } + } + + return super.getResource(name); + } + + /** + * {@inheritDoc} + */ + @Override + public Set getLibraryClasses() { + return Collections.unmodifiableSet(libraryClasses); + } + + /** + * {@inheritDoc} + */ + @Override + public Set getCompiledClasses() { + Set compiledClasses = classFileManager.getCompiledClasses() + .keySet(); + return Collections.unmodifiableSet(compiledClasses); + } + + /** + * Returns list of classes that are members of a package + * + * @param packageName + * package to search for classes + * @return list of classes that are package members + * @throws IOException + * if was unable to load class + */ + public Set getClassesForPackage(String packageName) + throws IOException { + Set result = new HashSet(); + + // load parent + ClassLoader parent = getParent(); + if (parent instanceof ScriptClassLoaderImpl) { + ScriptClassLoaderImpl pscl = (ScriptClassLoaderImpl) parent; + result.addAll(pscl.getClassesForPackage(packageName)); + } + + // load current classloader compiled classes + for (String cn : classFileManager.getCompiledClasses().keySet()) { + if (ClassUtils.isPackageMember(cn, packageName)) { + BinaryClass bc = classFileManager.getCompiledClasses().get(cn); + result.add(bc); + } + } + + // load libraries + for (String cn : libraryClasses) { + if (ClassUtils.isPackageMember(cn, packageName)) { + BinaryClass bc = new BinaryClass(cn); + try { + byte[] data = getRawClassByName(cn); + OutputStream os = bc.openOutputStream(); + os.write(data); + } catch (IOException e) { + log.error("Error while loading class from package " + + packageName, e); + throw e; + } + result.add(bc); + } + } + + return result; + } + + /** + * Finds class with the specified name from the URL search path. Any URLs + * referring to JAR files are loaded and opened as needed until the class is + * found. + * + * @param name + * the name of the class + * @return the resulting class data + * @throws IOException + * if the class could not be found + */ + protected byte[] getRawClassByName(String name) throws IOException { + URL resource = findResource(name.replace('.', '/').concat(".class")); + InputStream is = null; + byte[] clazz = null; + + try { + is = resource.openStream(); + clazz = IOUtils.toByteArray(is); + } catch (IOException e) { + log.error("Error while loading class data", e); + throw e; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + log.error("Error while closing stream", e); + } + } + } + return clazz; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ScriptCompilerImpl.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ScriptCompilerImpl.java new file mode 100644 index 000000000..df834a920 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/ScriptCompilerImpl.java @@ -0,0 +1,253 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import javax.tools.DiagnosticListener; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.l2jserver.service.game.scripting.CompilationResult; +import com.l2jserver.service.game.scripting.ScriptClassLoader; +import com.l2jserver.service.game.scripting.ScriptCompiler; + +/** + * Wrapper for JavaCompiler api + * + * @author Rogiel + */ +public class ScriptCompilerImpl implements ScriptCompiler { + + /** + * Logger for this class + */ + private static final Logger log = LoggerFactory + .getLogger(ScriptCompilerImpl.class); + + /** + * Instance of JavaCompiler that will be used to compile classes + */ + protected final JavaCompiler javaCompiler; + + /** + * List of jar files + */ + protected Iterable libraries; + + /** + * Parent classloader that has to be used for this compiler + */ + protected ScriptClassLoader parentClassLoader; + + /** + * Creates new instance of JavaCompilerImpl. If system compiler is not + * available - throws RuntimeExcetion + * + * @throws RuntimeException + * if compiler is not available + */ + public ScriptCompilerImpl() { + this.javaCompiler = ToolProvider.getSystemJavaCompiler(); + + if (javaCompiler == null) { + if (ToolProvider.getSystemJavaCompiler() != null) { + throw new RuntimeException(new InstantiationException( + "JavaCompiler is not aviable.")); + } + } + } + + /** + * Sets parent classLoader for this JavaCompilerImpl + * + * @param classLoader + * parent classloader + */ + @Override + public void setParentClassLoader(ScriptClassLoader classLoader) { + this.parentClassLoader = classLoader; + } + + /** + * Sets jar files that should be used for this compiler as libraries + * + * @param files + * list of jar files + */ + @Override + public void setLibraires(Iterable files) { + libraries = files; + } + + /** + * Compiles given class. + * + * @param className + * Name of the class + * @param sourceCode + * source code + * @return CompilationResult with the class + * @throws RuntimeException + * if compilation failed with errros + */ + @Override + public CompilationResult compile(String className, String sourceCode) { + return compile(new String[] { className }, new String[] { sourceCode }); + } + + /** + * Compiles list of classes. Amount of classNames must be equal to amount of + * sourceCodes + * + * @param classNames + * classNames + * @param sourceCode + * list of source codes + * @return CompilationResult with needed files + * @throws IllegalArgumentException + * if size of classNames not equals to size of sourceCodes + * @throws RuntimeException + * if compilation failed with errros + */ + @Override + public CompilationResult compile(String[] classNames, String[] sourceCode) + throws IllegalArgumentException { + + if (classNames.length != sourceCode.length) { + throw new IllegalArgumentException( + "Amount of classes is not equal to amount of sources"); + } + + List compilationUnits = new ArrayList(); + + for (int i = 0; i < classNames.length; i++) { + JavaFileObject compilationUnit = new JavaSourceFromString( + classNames[i], sourceCode[i]); + compilationUnits.add(compilationUnit); + } + + return doCompilation(compilationUnits); + } + + /** + * Compiles given files. Files must be java sources. + * + * @param compilationUnits + * files to compile + * @return CompilationResult with classes + * @throws RuntimeException + * if compilation failed with errros + */ + @Override + public CompilationResult compile(Iterable compilationUnits) { + List list = new ArrayList(); + + for (File f : compilationUnits) { + list.add(new JavaSourceFromFile(f, JavaFileObject.Kind.SOURCE)); + } + + return doCompilation(list); + } + + /** + * Actually performs compilation. Compiler expects sources in UTF-8 + * encoding. Also compiler generates full debugging info for classes. + * + * @param compilationUnits + * Units that will be compiled + * @return CompilationResult with compiledClasses + * @throws RuntimeException + * if compilation failed with errros + */ + protected CompilationResult doCompilation( + Iterable compilationUnits) { + List options = Arrays.asList("-encoding", "UTF-8", "-g"); + DiagnosticListener listener = new ErrorListener(); + ClassFileManager manager = new ClassFileManager(javaCompiler, listener); + manager.setParentClassLoader(parentClassLoader); + + if (libraries != null) { + try { + manager.addLibraries(libraries); + } catch (IOException e) { + log.error("Can't set libraries for compiler.", e); + } + } + + JavaCompiler.CompilationTask task = javaCompiler.getTask(null, manager, + listener, options, null, compilationUnits); + + if (!task.call()) { + throw new RuntimeException("Error while compiling classes"); + } + + ScriptClassLoader cl = manager.getClassLoader(null); + Class[] compiledClasses = classNamesToClasses(manager + .getCompiledClasses().keySet(), cl); + return new CompilationResult(compiledClasses, cl); + } + + /** + * Reolves list of classes by their names + * + * @param classNames + * names of the classes + * @param cl + * classLoader to use to resove classes + * @return resolved classes + * @throws RuntimeException + * if can't find class + */ + protected Class[] classNamesToClasses(Collection classNames, + ScriptClassLoader cl) { + Class[] classes = new Class[classNames.size()]; + + int i = 0; + for (String className : classNames) { + try { + Class clazz = cl.loadClass(className); + classes[i] = clazz; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + i++; + } + + return classes; + } + + /** + * Only java files are supported by java compiler + * + * @return "java"; + */ + @Override + public String[] getSupportedFileTypes() { + return new String[] { "java" }; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/VirtualClassURLConnection.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/VirtualClassURLConnection.java new file mode 100644 index 000000000..cd7a42ab5 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/VirtualClassURLConnection.java @@ -0,0 +1,75 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; + +/** + * This class represents URL Connection that is used to "connect" to scripts + * binary data that was loaded by specified + * {@link ScriptCompilerImpl}.
+ *
+ * TODO: Implement all methods of {@link URLConnection} to ensure valid + * behaviour + * + * @author Rogiel + */ +public class VirtualClassURLConnection extends URLConnection { + + /** + * Input stream, is assigned from class + */ + private InputStream is; + + /** + * Creates URL connections that "connects" to class binary data + * + * @param url + * class name + * @param cl + * classloader + */ + protected VirtualClassURLConnection(URL url, ScriptClassLoaderImpl cl) { + super(url); + BinaryClass bc = cl.getClassFileManager().getCompiledClasses() + .get(url.getHost()); + byte[] b = new byte[bc.getBytes().length]; + System.arraycopy(bc.getBytes(), 0, b, 0, b.length); + is = new ByteArrayInputStream(b); + } + + /** + * This method is ignored + */ + @Override + public void connect() throws IOException { + + } + + /** + * {@inheritDoc} + */ + @Override + public InputStream getInputStream() throws IOException { + return is; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/VirtualClassURLStreamHandler.java b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/VirtualClassURLStreamHandler.java new file mode 100644 index 000000000..8cc40257f --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/impl/javacc/VirtualClassURLStreamHandler.java @@ -0,0 +1,66 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.impl.javacc; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * This class represents URL Stream handler that accepts + * {@value #HANDLER_PROTOCOL} protocol + * + * @author Rogiel + */ +public class VirtualClassURLStreamHandler extends URLStreamHandler { + + /** + * Script Handler protocol for classes compiled from source + */ + public static final String HANDLER_PROTOCOL = "aescript://"; + + /** + * Script class loader that loaded those classes + */ + private final ScriptClassLoaderImpl cl; + + /** + * Creates new instance of url stream handler with given classloader + * + * @param cl + * ScriptClassLoaderImpl that was used to load compiled class + */ + public VirtualClassURLStreamHandler(ScriptClassLoaderImpl cl) { + this.cl = cl; + } + + /** + * Opens new URL connection for URL + * + * @param u + * url + * @return Opened connection + * @throws IOException + * never thrown + */ + @Override + protected URLConnection openConnection(URL u) throws IOException { + return new VirtualClassURLConnection(u, cl); + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/metadata/OnClassLoad.java b/src/main/java/com/l2jserver/service/game/scripting/metadata/OnClassLoad.java new file mode 100644 index 000000000..674bb3b18 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/metadata/OnClassLoad.java @@ -0,0 +1,56 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.metadata; + +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 com.l2jserver.service.game.scripting.ScriptContext; +import com.l2jserver.service.game.scripting.classlistener.DefaultClassListener; + +/** + * Method marked as {@link OnClassLoad} will be called when class was loaded by + * script.
+ * It's more useful alternative for + * + *
+ * static {
+ * 	...
+ * }
+ * 
+ * + * block.
+ *
+ * Only static methods with no arguments can be marked with this annotation.
+ * + * This is only used if + * {@link ScriptContext#getClassListener()} + * returns + * {@link DefaultClassListener} + * instance. + * + * @author Rogiel + */ +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface OnClassLoad { +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/metadata/OnClassUnload.java b/src/main/java/com/l2jserver/service/game/scripting/metadata/OnClassUnload.java new file mode 100644 index 000000000..a8547b964 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/metadata/OnClassUnload.java @@ -0,0 +1,46 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.metadata; + +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 com.l2jserver.service.game.scripting.ScriptContext; +import com.l2jserver.service.game.scripting.classlistener.DefaultClassListener; + +/** + * Method marked as {@link OnClassUnload} will be called when there is a script + * reload or shutdown.
+ * Only static methods with no arguments can be marked with this annotation.
+ * + * This is only used if + * {@link ScriptContext#getClassListener()} + * returns + * {@link DefaultClassListener} + * instance. + * + * @author Rogiel + */ +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface OnClassUnload { +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptInfo.java b/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptInfo.java new file mode 100644 index 000000000..b5779bbe4 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptInfo.java @@ -0,0 +1,173 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.scriptmanager; + +import java.io.File; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import com.l2jserver.service.game.scripting.impl.javacc.ScriptCompilerImpl; + +/** + * Simple class that represents script info.
+ *
+ * It contains Script root, list of libraries and list of child contexes + * + * @author Rogiel + */ +@XmlRootElement(name = "scriptinfo") +@XmlAccessorType(XmlAccessType.NONE) +public class ScriptInfo { + /** + * Root of this script context. Child directories of root will be scanned + * for script files + */ + @XmlAttribute(required = true) + private File root; + + /** + * List of libraries of this script context + */ + @XmlElement(name = "library") + private List libraries; + + /** + * List of child contexts + */ + @XmlElement(name = "scriptinfo") + private List scriptInfos; + + /** + * Default compiler class name. + */ + @XmlElement(name = "compiler") + private String compilerClass = ScriptCompilerImpl.class.getName(); + + /** + * Returns root of script context + * + * @return root of script context + */ + public File getRoot() { + return root; + } + + /** + * Sets root for script context + * + * @param root + * root for script context + */ + public void setRoot(File root) { + this.root = root; + } + + /** + * Returns list of libraries that will be used byscript context and it's + * children + * + * @return lib of libraries + */ + public List getLibraries() { + return libraries; + } + + /** + * Sets list of libraries that will be used by script context and it's + * children + * + * @param libraries + * sets list of libraries + */ + public void setLibraries(List libraries) { + this.libraries = libraries; + } + + /** + * Return list of child context descriptors + * + * @return list of child context descriptors + */ + public List getScriptInfos() { + return scriptInfos; + } + + /** + * Sets list of child context descriptors + * + * @param scriptInfos + * list of child context descriptors + */ + public void setScriptInfos(List scriptInfos) { + this.scriptInfos = scriptInfos; + } + + /** + * Returns compiler class name + * + * @return name of compiler class + */ + public String getCompilerClass() { + return compilerClass; + } + + /** + * Sets compiler class name + * + * @param compilerClass + * name of compiler class + */ + public void setCompilerClass(String compilerClass) { + this.compilerClass = compilerClass; + } + + /** + * Returns true if roots are quals + * + * @param o + * object to compare with + * @return true if this ScriptInfo and anothers ScriptInfo has same root + */ + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + ScriptInfo that = (ScriptInfo) o; + + return root.equals(that.root); + + } + + /** + * Returns hashcode of root + * + * @return hashcode of root + */ + @Override + public int hashCode() { + return root.hashCode(); + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptList.java b/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptList.java new file mode 100644 index 000000000..54276f257 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptList.java @@ -0,0 +1,59 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.scriptmanager; + +import java.util.Set; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Root element for script descriptors + * + * @author Rogiel + */ +@XmlRootElement(name = "scriptlist") +@XmlAccessorType(XmlAccessType.NONE) +public class ScriptList { + /** + * List of Script descriptors + */ + @XmlElement(name = "scriptinfo", type = ScriptInfo.class) + private Set scriptInfos; + + /** + * Returns list of script descriptors + * + * @return list of script descriptors + */ + public Set getScriptInfos() { + return scriptInfos; + } + + /** + * Sets list of script descriptors + * + * @param scriptInfos + * lisft of script descriptors + */ + public void setScriptInfos(Set scriptInfos) { + this.scriptInfos = scriptInfos; + } +} diff --git a/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptManager.java b/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptManager.java new file mode 100644 index 000000000..bd0cd29e9 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/scripting/scriptmanager/ScriptManager.java @@ -0,0 +1,148 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.service.game.scripting.scriptmanager; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.l2jserver.service.game.scripting.ScriptContext; +import com.l2jserver.service.game.scripting.ScriptContextFactory; + +/** + * Class that represents managers of script contexes. It loads, reloads and + * unload script contexes. In the future it may be extended to support + * programatic manipulation of contexes, but for now it's not needed. + * + * Example: + * + *
+ *      ScriptManager sm = new ScriptManager();
+ *      sm.load(new File("st/contexts.xml"));
+ *      ...
+ *      sm.shutdown();
+ * 
+ * + * @author Rogiel + */ +public class ScriptManager { + /** + * Logger for script context + */ + private static final Logger log = LoggerFactory + .getLogger(ScriptManager.class); + + /** + * Collection of script contexts + */ + private Set contexts = new HashSet(); + + /** + * Loads script contexes from descriptor + * + * @param scriptDescriptor + * xml file that describes contexes + * @throws Exception + * if can't load file + */ + public synchronized void load(File scriptDescriptor) throws Exception { + + JAXBContext c = JAXBContext.newInstance(ScriptInfo.class, + ScriptList.class); + Unmarshaller u = c.createUnmarshaller(); + ScriptList list = (ScriptList) u.unmarshal(scriptDescriptor); + + for (ScriptInfo si : list.getScriptInfos()) { + ScriptContext context = createContext(si, null); + if (context != null) { + contexts.add(context); + context.init(); + } + } + } + + /** + * Creates new context and checks to not produce copies + * + * @param si + * script context descriptor + * @param parent + * parent script context + * @return created script context + * @throws Exception + * if can't create context + */ + private ScriptContext createContext(ScriptInfo si, ScriptContext parent) + throws Exception { + ScriptContext context = ScriptContextFactory.getScriptContext( + si.getRoot(), parent); + context.setLibraries(si.getLibraries()); + context.setCompilerClassName(si.getCompilerClass()); + + if (parent == null && contexts.contains(context)) { + log.warn("Double root script context definition: " + + si.getRoot().getAbsolutePath()); + return null; + } + + if (si.getScriptInfos() != null && !si.getScriptInfos().isEmpty()) { + for (ScriptInfo child : si.getScriptInfos()) { + createContext(child, context); + } + } + + return context; + } + + /** + * Initializes shutdown on all contexes + */ + public synchronized void shutdown() { + for (ScriptContext context : contexts) { + context.shutdown(); + } + + contexts.clear(); + } + + /** + * Reloads all contexes + */ + public synchronized void reload() { + for (ScriptContext context : contexts) { + context.reload(); + } + } + + /** + * Returns unmodifiable set with script contexes + * + * @return unmodifiable set of script contexes + */ + public synchronized Collection getScriptContexts() { + return Collections.unmodifiableSet(contexts); + } +} diff --git a/src/main/java/com/l2jserver/util/ClassUtils.java b/src/main/java/com/l2jserver/util/ClassUtils.java new file mode 100644 index 000000000..36efad22e --- /dev/null +++ b/src/main/java/com/l2jserver/util/ClassUtils.java @@ -0,0 +1,94 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ + +package com.l2jserver.util; + +/** + * This class contains utilities that are used when we are working with classes + * + * @author Rogiel + */ +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 + * tht 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 + // primtitive type there is a unqiue 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); + } + } +} diff --git a/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java b/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java index b1a0a81af..3d1676996 100644 --- a/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java +++ b/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java @@ -4,9 +4,10 @@ import junit.framework.Assert; import org.junit.Test; +import script.dao.mysql5.DAOModuleMySQL5; + import com.google.inject.Guice; import com.google.inject.Injector; -import com.l2jserver.db.dao.mysql5.DAOModuleMySQL5; import com.l2jserver.model.id.CharacterID; import com.l2jserver.model.id.ID; import com.l2jserver.model.world.L2Character; diff --git a/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java b/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java index 4fbda3f3f..416f0fbad 100644 --- a/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java +++ b/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java @@ -7,11 +7,12 @@ import junit.framework.Assert; import org.junit.Before; import org.junit.Test; +import script.dao.mysql5.DAOModuleMySQL5; + import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Scopes; -import com.l2jserver.db.dao.mysql5.DAOModuleMySQL5; import com.l2jserver.model.id.factory.CharacterIDFactory; import com.l2jserver.model.id.factory.IDFactoryModule; import com.l2jserver.model.id.factory.ItemIDFactory;