| /* |
| * Copyright (c) 2008-2014 Eike Stepper (Berlin, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.emf.cdo.tests.config.impl; |
| |
| import org.eclipse.emf.cdo.common.model.EMFUtil; |
| import org.eclipse.emf.cdo.common.revision.CDORevisionManager; |
| import org.eclipse.emf.cdo.server.IRepository; |
| import org.eclipse.emf.cdo.session.CDOSession; |
| import org.eclipse.emf.cdo.session.CDOSessionConfiguration; |
| import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; |
| import org.eclipse.emf.cdo.spi.server.InternalRepository; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoChangeSets; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoCommitInfos; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoDurableLocking; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoExternalReferences; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoFeatureMaps; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoHandleRevisions; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoLargeObjects; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoQueryXRefs; |
| import org.eclipse.emf.cdo.spi.server.InternalStore.NoRawAccess; |
| import org.eclipse.emf.cdo.tests.config.IConstants; |
| import org.eclipse.emf.cdo.tests.config.IModelConfig; |
| import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; |
| import org.eclipse.emf.cdo.tests.config.IScenario; |
| import org.eclipse.emf.cdo.tests.config.ISessionConfig; |
| import org.eclipse.emf.cdo.tests.config.impl.SessionConfig.Net4j; |
| import org.eclipse.emf.cdo.tests.mango.MangoFactory; |
| import org.eclipse.emf.cdo.tests.mango.MangoPackage; |
| import org.eclipse.emf.cdo.tests.model1.Model1Factory; |
| import org.eclipse.emf.cdo.tests.model1.Model1Package; |
| import org.eclipse.emf.cdo.tests.model2.Model2Factory; |
| import org.eclipse.emf.cdo.tests.model2.Model2Package; |
| import org.eclipse.emf.cdo.tests.model3.Model3Factory; |
| import org.eclipse.emf.cdo.tests.model3.Model3Package; |
| import org.eclipse.emf.cdo.tests.model3.subpackage.SubpackageFactory; |
| import org.eclipse.emf.cdo.tests.model3.subpackage.SubpackagePackage; |
| import org.eclipse.emf.cdo.tests.model4.model4Factory; |
| import org.eclipse.emf.cdo.tests.model4.model4Package; |
| import org.eclipse.emf.cdo.tests.model4interfaces.model4interfacesPackage; |
| import org.eclipse.emf.cdo.tests.model5.Model5Factory; |
| import org.eclipse.emf.cdo.tests.model5.Model5Package; |
| import org.eclipse.emf.cdo.tests.model6.Model6Factory; |
| import org.eclipse.emf.cdo.tests.model6.Model6Package; |
| |
| import org.eclipse.net4j.util.ImplementationError; |
| import org.eclipse.net4j.util.ObjectUtil; |
| import org.eclipse.net4j.util.WrappedException; |
| import org.eclipse.net4j.util.container.IManagedContainer; |
| import org.eclipse.net4j.util.io.IOUtil; |
| import org.eclipse.net4j.util.lifecycle.LifecycleUtil; |
| import org.eclipse.net4j.util.security.IPasswordCredentials; |
| import org.eclipse.net4j.util.security.IPasswordCredentialsProvider; |
| import org.eclipse.net4j.util.security.PasswordCredentialsProvider; |
| import org.eclipse.net4j.util.tests.AbstractOMTest; |
| |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EcorePackage; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Inherited; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| import java.text.MessageFormat; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.concurrent.ExecutorService; |
| |
| import junit.framework.TestResult; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public abstract class ConfigTest extends AbstractOMTest implements IConstants |
| { |
| private static int dynamicPackageCounter; |
| |
| private transient int dynamicPackageNumber; |
| |
| private IScenario scenario; |
| |
| private Properties homeProperties; |
| |
| private Map<String, Object> testProperties; |
| |
| public ConfigTest() |
| { |
| } |
| |
| public ExecutorService getExecutorService() |
| { |
| return Config.getExecutorService(); |
| } |
| |
| public synchronized IScenario getScenario() |
| { |
| if (scenario == null) |
| { |
| setScenario(getDefaultScenario()); |
| } |
| |
| return scenario; |
| } |
| |
| public synchronized void setScenario(IScenario scenario) |
| { |
| this.scenario = scenario; |
| if (scenario != null) |
| { |
| scenario.setCurrentTest(this); |
| } |
| } |
| |
| public synchronized Properties getHomeProperties() |
| { |
| if (homeProperties == null) |
| { |
| homeProperties = new Properties(); |
| String home = System.getProperty("user.home"); |
| if (home != null) |
| { |
| File file = new File(home, ".cdo_config_test.properties"); |
| if (file.exists()) |
| { |
| FileInputStream stream = IOUtil.openInputStream(file); |
| |
| try |
| { |
| homeProperties.load(stream); |
| } |
| catch (IOException ex) |
| { |
| throw WrappedException.wrap(ex); |
| } |
| finally |
| { |
| IOUtil.close(stream); |
| } |
| } |
| } |
| } |
| |
| return homeProperties; |
| } |
| |
| public synchronized void setHomeProperties(Properties homeProperties) |
| { |
| this.homeProperties = homeProperties; |
| } |
| |
| public synchronized Map<String, Object> getTestProperties() |
| { |
| if (testProperties == null) |
| { |
| testProperties = new HashMap<String, Object>(); |
| } |
| |
| return testProperties; |
| } |
| |
| // ///////////////////////////////////////////////////////////////////////// |
| // //////////////////////// Repository ///////////////////////////////////// |
| |
| /** |
| * @category Repository |
| */ |
| public IRepositoryConfig getRepositoryConfig() |
| { |
| IScenario scenario = getScenario(); |
| return scenario.getRepositoryConfig(); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public Map<String, String> getRepositoryProperties() |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| return repositoryConfig.getRepositoryProperties(); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public boolean hasServerContainer() |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| return repositoryConfig.hasServerContainer(); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public IManagedContainer getServerContainer() |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| return repositoryConfig.getServerContainer(); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public InternalRepository getRepository(String name, boolean activate) |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| return repositoryConfig.getRepository(name, activate); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public InternalRepository getRepository(String name) |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| return repositoryConfig.getRepository(name); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public InternalRepository getRepository() |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| return repositoryConfig.getRepository(IRepositoryConfig.REPOSITORY_NAME); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public void registerRepository(IRepository repository) |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| repositoryConfig.registerRepository((InternalRepository)repository); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public InternalRepository restartRepository() |
| { |
| return restartRepository(IRepositoryConfig.REPOSITORY_NAME); |
| } |
| |
| /** |
| * @category Repository |
| */ |
| public InternalRepository restartRepository(String name) |
| { |
| IRepositoryConfig repositoryConfig = getRepositoryConfig(); |
| |
| try |
| { |
| repositoryConfig.setRestarting(true); |
| InternalRepository repo = getRepository(name); |
| LifecycleUtil.deactivate(repo); |
| return getRepository(name); |
| } |
| finally |
| { |
| repositoryConfig.setRestarting(false); |
| } |
| } |
| |
| // ///////////////////////////////////////////////////////////////////////// |
| // //////////////////////// Session //////////////////////////////////////// |
| |
| /** |
| * @category Session |
| */ |
| public ISessionConfig getSessionConfig() |
| { |
| IScenario scenario = getScenario(); |
| return scenario.getSessionConfig(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public boolean hasClientContainer() |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.hasClientContainer(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public IManagedContainer getClientContainer() |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.getClientContainer(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public void startTransport() throws Exception |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| sessionConfig.startTransport(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public String getTransportType() throws Exception |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| if (sessionConfig instanceof Net4j) |
| { |
| Net4j net4j = (Net4j)sessionConfig; |
| return net4j.getTransportType(); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @category Session |
| */ |
| public void stopTransport() throws Exception |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| sessionConfig.stopTransport(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public String getURIProtocol() |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.getURIProtocol(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public String getURIPrefix() |
| { |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.getURIPrefix(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public CDOSession openSession() |
| { |
| determineCodeLink(); |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.openSession(); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public CDOSession openSession(String repositoryName) |
| { |
| determineCodeLink(); |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.openSession(repositoryName); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public CDOSession openSession(CDOSessionConfiguration configuration) |
| { |
| determineCodeLink(); |
| ISessionConfig sessionConfig = getSessionConfig(); |
| return sessionConfig.openSession(configuration); |
| } |
| |
| /** |
| * @category Session |
| */ |
| public CDOSession openSession(IPasswordCredentials credentials) |
| { |
| if (credentials != null) |
| { |
| IPasswordCredentialsProvider credentialsProvider = new PasswordCredentialsProvider(credentials); |
| getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER, credentialsProvider); |
| } |
| else |
| { |
| getTestProperties().remove(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER); |
| } |
| |
| return openSession(); |
| } |
| |
| // ///////////////////////////////////////////////////////////////////////// |
| // //////////////////////// Model ////////////////////////////////////////// |
| |
| /** |
| * @category Model |
| */ |
| public IModelConfig getModelConfig() |
| { |
| IScenario scenario = getScenario(); |
| return scenario.getModelConfig(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public MangoFactory getMangoFactory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getMangoFactory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public MangoPackage getMangoPackage() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getMangoPackage(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model1Factory getModel1Factory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel1Factory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model1Package getModel1Package() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel1Package(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model2Factory getModel2Factory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel2Factory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model2Package getModel2Package() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel2Package(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model3Factory getModel3Factory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel3Factory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model3Package getModel3Package() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel3Package(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public SubpackageFactory getModel3SubpackageFactory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel3SubPackageFactory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public SubpackagePackage getModel3SubpackagePackage() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel3SubPackagePackage(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public model4Factory getModel4Factory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel4Factory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public model4Package getModel4Package() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel4Package(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public model4interfacesPackage getModel4InterfacesPackage() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel4InterfacesPackage(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model5Factory getModel5Factory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel5Factory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model5Package getModel5Package() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel5Package(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model6Factory getModel6Factory() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel6Factory(); |
| } |
| |
| /** |
| * @category Model |
| */ |
| public Model6Package getModel6Package() |
| { |
| IModelConfig modelConfig = getModelConfig(); |
| return modelConfig.getModel6Package(); |
| } |
| |
| // ///////////////////////////////////////////////////////////////////////// |
| // ///////////////////////////////////////////////////////////////////////// |
| |
| public boolean isValid() |
| { |
| return true; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return MessageFormat.format("{0}.{1} [{2}, {3}, {4}]", getClass().getSimpleName(), getName(), getRepositoryConfig(), |
| getSessionConfig(), getModelConfig()); |
| } |
| |
| @Override |
| public TestResult run() |
| { |
| try |
| { |
| return super.run(); |
| } |
| catch (ConfigTestException ex) |
| { |
| throw ex; |
| } |
| catch (Throwable ex) |
| { |
| throw new ConfigTestException("Error in " + this, ex); |
| } |
| } |
| |
| @Override |
| public void runBare() throws Throwable |
| { |
| try |
| { |
| super.runBare(); |
| } |
| catch (AssertionError error) |
| { |
| throw error; |
| } |
| catch (Throwable ex) |
| { |
| // We wrap anything that is not a test failure |
| throw new ConfigTestException("Error in " + this, ex); |
| } |
| } |
| |
| /** |
| * Constructs a test-specific resource path of the format "/TestClass_testMethod/resourceName". Using this instead of |
| * (just) a hardcoded name for the test resource, ensures that the test method is isolated from all others at the |
| * resource level. |
| * |
| * @param resourceName |
| * the test-local name of the resource or <code>null</code> for the path of the test-local root resource. |
| * @return the full path of the resource. |
| */ |
| public final String getResourcePath(String resourceName) |
| { |
| StringBuilder builder = new StringBuilder(); |
| builder.append('/'); |
| builder.append(getClass().getSimpleName()); // Name of this test class |
| builder.append('_'); |
| builder.append(getName()); // Name of the executing test method |
| |
| if (resourceName == null || resourceName.length() == 0 || resourceName.charAt(0) != '/') |
| { |
| builder.append('/'); |
| } |
| |
| if (resourceName != null) |
| { |
| builder.append(resourceName); |
| } |
| |
| return builder.toString(); |
| } |
| |
| /** |
| * Constructs a test-specific EPackage of the format "pkg123_name". Using this instead of |
| * (just) a hardcoded name for the test package, ensures that the test method is isolated from all others. |
| * |
| * @param name |
| * the test-local name of the package or <code>null</code> . |
| * @return the created package. |
| * @see #createUniquePackage() |
| */ |
| public final EPackage createUniquePackage(String name) |
| { |
| if (dynamicPackageNumber == 0) |
| { |
| dynamicPackageNumber = ++dynamicPackageCounter; |
| } |
| |
| StringBuilder builder = new StringBuilder(); |
| builder.append("pkg"); |
| builder.append(dynamicPackageNumber); |
| |
| if (name != null) |
| { |
| builder.append('_'); |
| builder.append(name); |
| } |
| |
| final String uniqueName = builder.toString(); |
| |
| EPackage ePackage = EMFUtil.createEPackage(uniqueName, uniqueName, "http://" + uniqueName); |
| ePackage.eAdapters().add(new AdapterImpl() |
| { |
| @Override |
| public void notifyChanged(Notification msg) |
| { |
| if (msg.isTouch()) |
| { |
| return; |
| } |
| |
| Object feature = msg.getFeature(); |
| if (feature == EcorePackage.Literals.EPACKAGE__NS_PREFIX || feature == EcorePackage.Literals.EPACKAGE__NS_URI |
| || feature == EcorePackage.Literals.ENAMED_ELEMENT__NAME) |
| { |
| throw new ImplementationError("Don't change the unique package " + uniqueName); |
| } |
| } |
| }); |
| |
| return ePackage; |
| } |
| |
| /** |
| * @see #createUniquePackage(String) |
| */ |
| public final EPackage createUniquePackage() |
| { |
| return createUniquePackage(null); |
| } |
| |
| protected boolean isConfig(Config config) |
| { |
| return ObjectUtil.equals(getRepositoryConfig(), config) // |
| || ObjectUtil.equals(getSessionConfig(), config) // |
| || ObjectUtil.equals(getModelConfig(), config); |
| } |
| |
| protected void skipStoreWithoutExternalReferences() |
| { |
| skipTest(getRepository().getStore() instanceof NoExternalReferences); |
| } |
| |
| protected void skipStoreWithoutQueryXRefs() |
| { |
| skipTest(getRepository().getStore() instanceof NoQueryXRefs); |
| } |
| |
| protected void skipStoreWithoutLargeObjects() |
| { |
| skipTest(getRepository().getStore() instanceof NoLargeObjects); |
| } |
| |
| protected void skipStoreWithoutFeatureMaps() |
| { |
| skipTest(getRepository().getStore() instanceof NoFeatureMaps); |
| } |
| |
| protected void skipStoreWithoutHandleRevisions() |
| { |
| skipTest(getRepository().getStore() instanceof NoHandleRevisions); |
| } |
| |
| protected void skipStoreWithoutRawAccess() |
| { |
| skipTest(getRepository().getStore() instanceof NoRawAccess); |
| } |
| |
| protected void skipStoreWithoutChangeSets() |
| { |
| skipTest(getRepository().getStore() instanceof NoChangeSets); |
| } |
| |
| protected void skipStoreWithoutCommitInfos() |
| { |
| skipTest(getRepository().getStore() instanceof NoCommitInfos); |
| } |
| |
| protected void skipStoreWithoutDurableLocking() |
| { |
| skipTest(getRepository().getStore() instanceof NoDurableLocking); |
| } |
| |
| protected void clearCache(CDORevisionManager revisionManager) |
| { |
| ((InternalCDORevisionManager)revisionManager).getCache().clear(); |
| } |
| |
| public void restartScenario() throws Exception |
| { |
| IOUtil.OUT().println("RESTARTING SCENARIO"); |
| stopTransport(); |
| |
| IScenario scenario = getScenario(); |
| scenario.tearDown(); |
| scenario.setUp(); |
| |
| startTransport(); |
| IOUtil.OUT().println("RESTARTING SCENARIO - FINISHED"); |
| } |
| |
| protected IScenario getDefaultScenario() |
| { |
| IScenario scenario; |
| |
| try |
| { |
| scenario = Scenario.load(); |
| if (scenario == null) |
| { |
| scenario = Scenario.getDefault(); |
| } |
| } |
| catch (Exception ex) |
| { |
| scenario = Scenario.getDefault(); |
| } |
| |
| return scenario; |
| } |
| |
| @Override |
| public void setUp() throws Exception |
| { |
| getScenario(); |
| super.setUp(); |
| } |
| |
| @Override |
| protected void doSetUp() throws Exception |
| { |
| super.doSetUp(); |
| getScenario().setUp(); |
| } |
| |
| @Override |
| protected void doTearDown() throws Exception |
| { |
| try |
| { |
| getScenario().tearDown(); |
| |
| if (testProperties != null) |
| { |
| testProperties.clear(); |
| testProperties = null; |
| } |
| |
| if (homeProperties != null) |
| { |
| homeProperties.clear(); |
| homeProperties = null; |
| } |
| } |
| catch (Exception ex) |
| { |
| IOUtil.print(ex); |
| } |
| |
| try |
| { |
| super.doTearDown(); |
| } |
| catch (Exception ex) |
| { |
| IOUtil.print(ex); |
| } |
| } |
| |
| @Inherited |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target({ ElementType.TYPE, ElementType.METHOD }) |
| public @interface CleanRepositoriesBefore |
| { |
| String reason(); |
| } |
| |
| @Inherited |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target({ ElementType.TYPE, ElementType.METHOD }) |
| public @interface CleanRepositoriesAfter |
| { |
| String reason(); |
| } |
| |
| @Inherited |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target({ ElementType.TYPE, ElementType.METHOD }) |
| public @interface Requires |
| { |
| String[]value(); |
| } |
| |
| @Inherited |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target({ ElementType.TYPE, ElementType.METHOD }) |
| public @interface Skips |
| { |
| String[]value(); |
| } |
| } |