/* * This file is part of Mixin, licensed under the MIT License (MIT). * * Copyright (c) SpongePowered * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.spongepowered.asm.service; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.spongepowered.asm.launch.platform.IMixinPlatformAgent; import org.spongepowered.asm.launch.platform.IMixinPlatformServiceAgent; import org.spongepowered.asm.launch.platform.container.IContainerHandle; import org.spongepowered.asm.logging.ILogger; import org.spongepowered.asm.logging.LoggerAdapterDefault; import org.spongepowered.asm.mixin.MixinEnvironment.CompatibilityLevel; import org.spongepowered.asm.mixin.MixinEnvironment.Phase; import org.spongepowered.asm.util.Constants; import org.spongepowered.asm.util.IConsumer; import org.spongepowered.asm.util.ReEntranceLock; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; /** * Mixin Service base class */ public abstract class MixinServiceAbstract implements IMixinService { // Consts protected static final String LAUNCH_PACKAGE = "org.spongepowered.asm.launch."; protected static final String MIXIN_PACKAGE = "org.spongepowered.asm.mixin."; protected static final String SERVICE_PACKAGE = "org.spongepowered.asm.service."; /** * Cached logger adapters */ private static final Map loggers = new HashMap(); /** * Transformer re-entrance lock, shared between the mixin transformer and * the metadata service */ protected final ReEntranceLock lock = new ReEntranceLock(1); /** * All internals offered to this service */ private final Map, IMixinInternal> internals = new HashMap, IMixinInternal>(); /** * Service agent instances */ private List serviceAgents; /** * Detected side name */ private String sideName; /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#prepare() */ @Override public void prepare() { } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#getInitialPhase() */ @Override public Phase getInitialPhase() { return Phase.PREINIT; } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService * #getMinCompatibilityLevel() */ @Override public CompatibilityLevel getMinCompatibilityLevel() { return null; } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService * #getMaxCompatibilityLevel() */ @Override public CompatibilityLevel getMaxCompatibilityLevel() { return null; } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService * #offer(org.spongepowered.asm.service.IMixinInternal) */ @Override public void offer(IMixinInternal internal) { this.registerInternal(internal, internal.getClass()); } @SuppressWarnings("unchecked") private void registerInternal(IMixinInternal internal, Class clazz) { for (Class iface : clazz.getInterfaces()) { if (iface == IMixinInternal.class) { this.internals.put((Class)clazz, internal); } this.registerInternal(internal, iface); } } @SuppressWarnings("unchecked") protected final T getInternal(Class type) { for (Class internalType : this.internals.keySet()) { if (type.isAssignableFrom(internalType)) { return (T)this.internals.get(internalType); } } return null; } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#init() */ @Override public void init() { for (IMixinPlatformServiceAgent agent : this.getServiceAgents()) { agent.init(); } } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#beginPhase() */ @Override public void beginPhase() { } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService * #checkEnv(java.lang.Object) */ @Override public void checkEnv(Object bootSource) { } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#getReEntranceLock() */ @Override public ReEntranceLock getReEntranceLock() { return this.lock; } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#getMixinContainers() */ @Override public Collection getMixinContainers() { Builder list = ImmutableList.builder(); this.getContainersFromAgents(list); return list.build(); } /** * Collect mixin containers from platform agents */ protected final void getContainersFromAgents(Builder list) { for (IMixinPlatformServiceAgent agent : this.getServiceAgents()) { Collection containers = agent.getMixinContainers(); if (containers != null) { list.addAll(containers); } } } /* (non-Javadoc) * @see org.spongepowered.asm.service.IMixinService#getSideName() */ @Override public final String getSideName() { if (this.sideName != null) { return this.sideName; } for (IMixinPlatformServiceAgent agent : this.getServiceAgents()) { try { String side = agent.getSideName(); if (side != null) { return this.sideName = side; } } catch (Exception ex) { this.getLogger("mixin").catching(ex); } } return Constants.SIDE_UNKNOWN; } private List getServiceAgents() { if (this.serviceAgents != null) { return this.serviceAgents; } this.serviceAgents = new ArrayList(); for (String agentClassName : this.getPlatformAgents()) { try { @SuppressWarnings("unchecked") Class agentClass = (Class)this.getClassProvider().findClass(agentClassName, false); IMixinPlatformAgent agent = agentClass.getDeclaredConstructor().newInstance(); if (agent instanceof IMixinPlatformServiceAgent) { this.serviceAgents.add((IMixinPlatformServiceAgent)agent); } } catch (Exception ex) { // Bad? ex.printStackTrace(); } } return this.serviceAgents; } @Override public synchronized ILogger getLogger(final String name) { ILogger logger = MixinServiceAbstract.loggers.get(name); if (logger == null) { MixinServiceAbstract.loggers.put(name, logger = this.createLogger(name)); } return logger; } protected ILogger createLogger(final String name) { return new LoggerAdapterDefault(name); } // AMS - TEMP WIRING TO AVOID THE COMPLEXITY OF MERGING MULTIPHASE WITH 0.8 /** * Temp wiring. Called when the initial phase is spun up in the environment. * * @param phase Initial phase * @param phaseConsumer Delegate for the service (or agents) to trigger * later phases * @deprecated temporary */ @Deprecated public void wire(Phase phase, IConsumer phaseConsumer) { for (IMixinPlatformServiceAgent agent : this.getServiceAgents()) { agent.wire(phase, phaseConsumer); } } /** * Temp wiring. Called when the default phase is started in the environment. * @deprecated temporary */ @Deprecated public void unwire() { for (IMixinPlatformServiceAgent agent : this.getServiceAgents()) { agent.unwire(); } } }