runelite-client: dynamically find plugins from classpath scanning

This commit is contained in:
Adam
2017-10-20 17:20:58 -04:00
parent 750e25bd12
commit e0e07a4fb8
32 changed files with 220 additions and 68 deletions

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface PluginDescriptor
{
String name();
boolean developerPlugin() default false;
}

View File

@@ -24,46 +24,19 @@
*/
package net.runelite.client.plugins;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service;
import com.google.common.util.concurrent.ServiceManager;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.account.AccountPlugin;
import net.runelite.client.plugins.boosts.Boosts;
import net.runelite.client.plugins.bosstimer.BossTimers;
import net.runelite.client.plugins.chatcommands.ChatCommands;
import net.runelite.client.plugins.clanchat.ClanChat;
import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin;
import net.runelite.client.plugins.combatnotifier.CombatNotifier;
import net.runelite.client.plugins.config.ConfigPlugin;
import net.runelite.client.plugins.devtools.DevTools;
import net.runelite.client.plugins.examine.ExaminePlugin;
import net.runelite.client.plugins.fightcave.FightCave;
import net.runelite.client.plugins.fishing.FishingPlugin;
import net.runelite.client.plugins.fpsinfo.FPS;
import net.runelite.client.plugins.grounditems.GroundItems;
import net.runelite.client.plugins.hiscore.Hiscore;
import net.runelite.client.plugins.idlenotifier.IdleNotifier;
import net.runelite.client.plugins.implings.Implings;
import net.runelite.client.plugins.jewelrycount.JewelryCount;
import net.runelite.client.plugins.mousehighlight.MouseHighlight;
import net.runelite.client.plugins.opponentinfo.OpponentInfo;
import net.runelite.client.plugins.pestcontrol.PestControl;
import net.runelite.client.plugins.chatcommands.ChatCommands;
import net.runelite.client.plugins.rememberusername.RememberUsername;
import net.runelite.client.plugins.runecraft.Runecraft;
import net.runelite.client.plugins.runepouch.Runepouch;
import net.runelite.client.plugins.timers.Timers;
import net.runelite.client.plugins.woodcutting.WoodcuttingPlugin;
import net.runelite.client.plugins.xpglobes.XpGlobes;
import net.runelite.client.plugins.xptracker.XPTracker;
import net.runelite.client.plugins.xtea.Xtea;
import net.runelite.client.plugins.zulrah.Zulrah;
import net.runelite.client.task.Schedule;
import net.runelite.client.task.ScheduledMethod;
import org.slf4j.Logger;
@@ -73,6 +46,8 @@ public class PluginManager
{
private static final Logger logger = LoggerFactory.getLogger(PluginManager.class);
private static final String PLUGIN_PACKAGE = "net.runelite.client.plugins";
private final RuneLite runelite;
private ServiceManager manager;
private final List<Plugin> plugins = new ArrayList<>();
@@ -82,42 +57,58 @@ public class PluginManager
this.runelite = runelite;
}
public void loadPlugins()
public void loadPlugins() throws IOException
{
plugins.add(new Boosts());
plugins.add(new OpponentInfo());
plugins.add(new FPS());
plugins.add(new Hiscore());
plugins.add(new BossTimers());
plugins.add(new Xtea());
plugins.add(new IdleNotifier());
plugins.add(new Runecraft());
plugins.add(new MouseHighlight());
plugins.add(new PestControl());
plugins.add(new ClanChat());
plugins.add(new Zulrah());
plugins.add(new AccountPlugin());
plugins.add(new ConfigPlugin());
plugins.add(new GroundItems());
plugins.add(new Implings());
plugins.add(new XpGlobes());
plugins.add(new CombatNotifier());
plugins.add(new JewelryCount());
plugins.add(new XPTracker());
plugins.add(new ExaminePlugin());
plugins.add(new FishingPlugin());
plugins.add(new WoodcuttingPlugin());
plugins.add(new RememberUsername());
plugins.add(new ChatCommands());
plugins.add(new ClueScrollPlugin());
plugins.add(new Timers());
plugins.add(new Runepouch());
plugins.add(new FightCave());
boolean developerPlugins = false;
if (RuneLite.getOptions().has("developer-mode"))
{
logger.info("Loading developer plugins");
plugins.add(new DevTools());
developerPlugins = true;
}
ClassPath classPath = ClassPath.from(getClass().getClassLoader());
ImmutableSet<ClassInfo> classes = classPath.getTopLevelClassesRecursive(PLUGIN_PACKAGE);
for (ClassInfo classInfo : classes)
{
Class<?> clazz = classInfo.load();
PluginDescriptor pluginDescriptor = clazz.getAnnotation(PluginDescriptor.class);
if (pluginDescriptor == null)
{
if (clazz.getSuperclass() == Plugin.class)
{
logger.warn("Class {} is a plugin, but has no plugin descriptor",
clazz);
}
continue;
}
if (clazz.getSuperclass() != Plugin.class)
{
logger.warn("Class {} has plugin descriptor, but is not a plugin",
clazz);
continue;
}
if (pluginDescriptor.developerPlugin() && !developerPlugins)
{
continue;
}
Plugin plugin;
try
{
plugin = (Plugin) clazz.newInstance();
}
catch (InstantiationException | IllegalAccessException ex)
{
logger.warn("error initializing plugin", ex);
continue;
}
plugins.add(plugin);
logger.debug("Loaded plugin {}", pluginDescriptor.name());
}
}

View File

@@ -39,6 +39,7 @@ import net.runelite.client.account.AccountSession;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.PluginToolbar;
@@ -49,6 +50,9 @@ import net.runelite.http.api.ws.messages.LoginResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Account plugin"
)
public class AccountPlugin extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(AccountPlugin.class);

View File

@@ -27,8 +27,12 @@ package net.runelite.client.plugins.boosts;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Boosts plugin"
)
public class Boosts extends Plugin
{
private final BoostsConfig config = RuneLite.getRunelite().getConfigManager().getConfig(BoostsConfig.class);

View File

@@ -30,10 +30,14 @@ import net.runelite.api.Actor;
import net.runelite.client.RuneLite;
import net.runelite.client.events.ActorDeath;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Boss timers"
)
public class BossTimers extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(BossTimers.class);

View File

@@ -39,6 +39,7 @@ import net.runelite.client.RuneLite;
import net.runelite.client.events.SetMessage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.http.api.hiscore.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreSkill;
import net.runelite.http.api.hiscore.SingleHiscoreSkillResult;
@@ -50,6 +51,9 @@ import net.runelite.http.api.item.SearchResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Chat commands"
)
public class ChatCommands extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(ChatCommands.class);

View File

@@ -30,8 +30,12 @@ import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
@PluginDescriptor(
name = "Clan chat plugin"
)
public class ClanChat extends Plugin
{
@Override

View File

@@ -34,8 +34,12 @@ import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
@PluginDescriptor(
name = "Clue scroll plugin"
)
public class ClueScrollPlugin extends Plugin
{
private final Client client = RuneLite.getClient();

View File

@@ -35,8 +35,12 @@ import net.runelite.api.Player;
import net.runelite.client.RuneLite;
import net.runelite.client.events.GameStateChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
@PluginDescriptor(
name = "Combat notifier"
)
public class CombatNotifier extends Plugin
{
private final Client client = RuneLite.getClient();

View File

@@ -28,11 +28,15 @@ import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Config plugin"
)
public class ConfigPlugin extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(ConfigPlugin.class);

View File

@@ -31,11 +31,16 @@ import net.runelite.api.widgets.Widget;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Developer tools",
developerPlugin = true
)
public class DevTools extends Plugin
{
private final DevToolsOverlay overlay = new DevToolsOverlay(this);

View File

@@ -37,6 +37,7 @@ import net.runelite.client.events.ChatMessage;
import net.runelite.client.events.GameStateChanged;
import net.runelite.client.events.MenuOptionClicked;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.http.api.examine.ExamineClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,6 +47,9 @@ import org.slf4j.LoggerFactory;
*
* @author Adam
*/
@PluginDescriptor(
name = "Examine plugin"
)
public class ExaminePlugin extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(ExaminePlugin.class);

View File

@@ -35,7 +35,11 @@ import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.Overlay;
import java.time.temporal.ChronoUnit;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Fight cave plugin"
)
public class FightCave extends Plugin
{
private final RuneLite runelite = RuneLite.getRunelite();

View File

@@ -35,9 +35,13 @@ import net.runelite.client.RuneLite;
import net.runelite.client.events.ChatMessage;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Fishing plugin"
)
public class FishingPlugin extends Plugin
{
private final RuneLite runelite = RuneLite.getRunelite();

View File

@@ -27,9 +27,13 @@ package net.runelite.client.plugins.fpsinfo;
import java.awt.Font;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Frames per second"
)
public class FPS extends Plugin
{
private final Overlay overlay = new FPSOverlay(this);

View File

@@ -26,8 +26,12 @@ package net.runelite.client.plugins.grounditems;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Ground items plugin"
)
public class GroundItems extends Plugin
{
private final GroundItemsConfig config = RuneLite.getRunelite().getConfigManager()

View File

@@ -31,11 +31,15 @@ import javax.swing.ImageIcon;
import net.runelite.client.RuneLite;
import net.runelite.client.events.PlayerMenuOptionClicked;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Hiscore plugin"
)
public class Hiscore extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(Hiscore.class);

View File

@@ -35,8 +35,12 @@ import net.runelite.api.Player;
import net.runelite.client.RuneLite;
import net.runelite.client.events.AnimationChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
@PluginDescriptor(
name = "Idle notifier"
)
public class IdleNotifier extends Plugin
{
private static final Duration WAIT_DURATION = Duration.ofMillis(2500L);

View File

@@ -28,12 +28,16 @@ import com.google.common.eventbus.Subscribe;
import net.runelite.client.RuneLite;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
/**
*
* @author robin
*/
@PluginDescriptor(
name = "Implings plugin"
)
public class Implings extends Plugin
{

View File

@@ -26,8 +26,12 @@ package net.runelite.client.plugins.jewelrycount;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Jewelry plugin"
)
public class JewelryCount extends Plugin
{
private final JewelryCountConfig config = RuneLite.getRunelite().getConfigManager().getConfig(JewelryCountConfig.class);

View File

@@ -26,8 +26,12 @@ package net.runelite.client.plugins.mousehighlight;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Mouse highlight plugin"
)
public class MouseHighlight extends Plugin
{
private final MouseHighlightConfig config = RuneLite.getRunelite().getConfigManager().getConfig(MouseHighlightConfig.class);

View File

@@ -32,8 +32,12 @@ import java.lang.reflect.Type;
import java.util.Map;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Opponent information plugin"
)
public class OpponentInfo extends Plugin
{
private final OpponentConfig config = RuneLite.getRunelite().getConfigManager().getConfig(OpponentConfig.class);

View File

@@ -26,9 +26,13 @@ package net.runelite.client.plugins.pestcontrol;
import java.awt.Font;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Pest control plugin"
)
public class PestControl extends Plugin
{
private final Overlay overlay = new PestControlOverlay(this);

View File

@@ -30,7 +30,11 @@ import net.runelite.api.GameState;
import net.runelite.client.RuneLite;
import net.runelite.client.events.GameStateChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Remember username plugin"
)
public class RememberUsername extends Plugin
{
private final Client client = RuneLite.getClient();

View File

@@ -34,8 +34,12 @@ import net.runelite.api.ChatMessageType;
import net.runelite.client.RuneLite;
import net.runelite.client.events.ChatMessage;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Runecraft plugin"
)
public class Runecraft extends Plugin
{
private static Pattern bindNeckString = Pattern.compile("You have ([0-9]+) charges left before your Binding necklace disintegrates.");

View File

@@ -26,8 +26,12 @@ package net.runelite.client.plugins.runepouch;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Runepouch plugin"
)
public class Runepouch extends Plugin
{
private final RunepouchConfig config = RuneLite.getRunelite().getConfigManager().getConfig(RunepouchConfig.class);

View File

@@ -30,9 +30,13 @@ import net.runelite.client.RuneLite;
import net.runelite.client.events.ChatMessage;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import static net.runelite.client.plugins.timers.GameTimer.*;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@PluginDescriptor(
name = "Timers plugin"
)
public class Timers extends Plugin
{
private final TimersConfig config = RuneLite.getRunelite().getConfigManager().getConfig(TimersConfig.class);

View File

@@ -32,9 +32,13 @@ import net.runelite.api.ChatMessageType;
import net.runelite.client.RuneLite;
import net.runelite.client.events.ChatMessage;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.Overlay;
@PluginDescriptor(
name = "Woodcutting plugin"
)
public class WoodcuttingPlugin extends Plugin
{
private final RuneLite runelite = RuneLite.getRunelite();

View File

@@ -25,6 +25,10 @@
package net.runelite.client.plugins.xpglobes;
import com.google.common.eventbus.Subscribe;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
@@ -32,13 +36,12 @@ import net.runelite.client.RuneLite;
import net.runelite.client.events.ExperienceChanged;
import net.runelite.client.events.GameStateChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.Overlay;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@PluginDescriptor(
name = "Xp Globes plugin"
)
public class XpGlobes extends Plugin
{

View File

@@ -35,8 +35,12 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
import java.time.temporal.ChronoUnit;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
@PluginDescriptor(
name = "XP Tracker plugin"
)
public class XPTracker extends Plugin
{
private static final int NUMBER_OF_SKILLS = Skill.values().length - 1; //ignore overall

View File

@@ -33,11 +33,15 @@ import net.runelite.api.Client;
import net.runelite.client.RuneLite;
import net.runelite.client.events.MapRegionChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.http.api.xtea.XteaClient;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Xtea plugin"
)
public class Xtea extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(Xtea.class);

View File

@@ -37,6 +37,7 @@ import net.runelite.api.Query;
import net.runelite.api.queries.NPCQuery;
import net.runelite.client.RuneLite;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.zulrah.patterns.ZulrahPattern;
import net.runelite.client.plugins.zulrah.patterns.ZulrahPatternA;
import net.runelite.client.plugins.zulrah.patterns.ZulrahPatternB;
@@ -47,6 +48,9 @@ import net.runelite.client.ui.overlay.Overlay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@PluginDescriptor(
name = "Zulrah plugin"
)
public class Zulrah extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(Zulrah.class);