| /******************************************************************************* |
| * Copyright (c) 2015 University of York. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the Eclipse |
| * Public License, v. 2.0 are satisfied: GNU General Public License, version 3. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 |
| * |
| * Contributors: |
| * Antonio Garcia-Dominguez - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.hawk.service.remote.thrift; |
| |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.ScheduledFuture; |
| import java.util.function.Supplier; |
| |
| import org.apache.activemq.artemis.api.core.client.ClientMessage; |
| import org.apache.activemq.artemis.api.core.client.MessageHandler; |
| import org.apache.thrift.TException; |
| import org.apache.thrift.protocol.TProtocol; |
| import org.eclipse.hawk.core.IConsole; |
| import org.eclipse.hawk.core.ICredentialsStore; |
| import org.eclipse.hawk.core.IMetaModelIntrospector; |
| import org.eclipse.hawk.core.IMetaModelResourceFactory; |
| import org.eclipse.hawk.core.IMetaModelUpdater; |
| import org.eclipse.hawk.core.IModelIndexer; |
| import org.eclipse.hawk.core.IModelResourceFactory; |
| import org.eclipse.hawk.core.IModelUpdater; |
| import org.eclipse.hawk.core.IStateListener; |
| import org.eclipse.hawk.core.IVcsManager; |
| import org.eclipse.hawk.core.VcsCommitItem; |
| import org.eclipse.hawk.core.VcsRepositoryDelta; |
| import org.eclipse.hawk.core.graph.IGraphChangeListener; |
| import org.eclipse.hawk.core.graph.IGraphDatabase; |
| import org.eclipse.hawk.core.graph.IGraphNode; |
| import org.eclipse.hawk.core.query.IAccessListener; |
| import org.eclipse.hawk.core.query.IQueryEngine; |
| import org.eclipse.hawk.core.query.InvalidQueryException; |
| import org.eclipse.hawk.core.query.QueryExecutionException; |
| import org.eclipse.hawk.core.runtime.CompositeGraphChangeListener; |
| import org.eclipse.hawk.core.runtime.CompositeStateListener; |
| import org.eclipse.hawk.core.util.DerivedAttributeParameters; |
| import org.eclipse.hawk.core.util.HawkProperties; |
| import org.eclipse.hawk.core.util.IndexedAttributeParameters; |
| import org.eclipse.hawk.osgiserver.HManager; |
| import org.eclipse.hawk.service.api.utils.APIUtils; |
| import org.eclipse.hawk.service.api.utils.ActiveMQBufferTransport; |
| import org.eclipse.hawk.service.api.utils.APIUtils.ThriftProtocol; |
| import org.eclipse.hawk.service.artemis.consumer.Consumer; |
| import org.eclipse.hawk.service.api.Credentials; |
| import org.eclipse.hawk.service.api.DerivedAttributeSpec; |
| import org.eclipse.hawk.service.api.FailedQuery; |
| import org.eclipse.hawk.service.api.Hawk.Client; |
| import org.eclipse.hawk.service.api.HawkInstance; |
| import org.eclipse.hawk.service.api.HawkInstanceNotFound; |
| import org.eclipse.hawk.service.api.HawkQueryOptions; |
| import org.eclipse.hawk.service.api.HawkState; |
| import org.eclipse.hawk.service.api.HawkStateEvent; |
| import org.eclipse.hawk.service.api.IndexedAttributeSpec; |
| import org.eclipse.hawk.service.api.InvalidQuery; |
| import org.eclipse.hawk.service.api.MetamodelParserDetails; |
| import org.eclipse.hawk.service.api.QueryReport; |
| import org.eclipse.hawk.service.api.Repository; |
| import org.eclipse.hawk.service.api.Subscription; |
| import org.eclipse.hawk.service.api.SubscriptionDurability; |
| import org.eclipse.hawk.service.api.UnknownQueryLanguage; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.thoughtworks.xstream.XStream; |
| import com.thoughtworks.xstream.io.xml.DomDriver; |
| |
| public class ThriftRemoteModelIndexer implements IModelIndexer, IMetaModelIntrospector { |
| |
| private final static Logger LOGGER = LoggerFactory.getLogger(ThriftRemoteModelIndexer.class); |
| |
| private final class StatePropagationConsumer implements MessageHandler { |
| private long currentTimestamp = 0; |
| private HawkState currentState; |
| private String currentInfo; |
| |
| public StatePropagationConsumer(HawkState state, String info) { |
| this.currentState = state; |
| this.currentInfo = info; |
| fireState(); |
| fireInfo(); |
| } |
| |
| @Override |
| public void onMessage(ClientMessage message) { |
| final TProtocol proto = ThriftProtocol.JSON.getProtocolFactory().getProtocol(new ActiveMQBufferTransport(message.getBodyBuffer())); |
| final HawkStateEvent change = new HawkStateEvent(); |
| try { |
| change.read(proto); |
| if (message.getTimestamp() < currentTimestamp) { |
| return; |
| } |
| currentTimestamp = message.getTimestamp(); |
| |
| if (change.getState() != currentState) { |
| currentState = change.getState(); |
| fireState(); |
| } |
| if (!change.getMessage().equals(currentInfo)) { |
| currentInfo = change.getMessage(); |
| fireInfo(); |
| } |
| } catch (Exception ex) { |
| Activator.logError(ex); |
| } |
| } |
| |
| protected void fireInfo() { |
| getCompositeStateListener().info(currentInfo); |
| } |
| |
| protected void fireState() { |
| switch (currentState) { |
| case RUNNING: |
| stateListener.state(IStateListener.HawkState.RUNNING); |
| break; |
| case STOPPED: |
| stateListener.state(IStateListener.HawkState.STOPPED); |
| break; |
| case UPDATING: |
| stateListener.state(IStateListener.HawkState.UPDATING); |
| break; |
| } |
| } |
| } |
| |
| private final class RemoteQueryEngine implements IQueryEngine { |
| private final String language; |
| private String defaultNamespaces = ""; |
| |
| private RemoteQueryEngine(String language) { |
| this.language = language; |
| } |
| |
| @Override |
| public List<String> validate(String derivationlogic) { |
| // TODO should we add something for this in the API? |
| // Right now we don't have a way to validate derived |
| // attribute expressions for remote Hawk instances. |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public String getType() { |
| return language; |
| } |
| |
| @Override |
| public Object query(IModelIndexer m, String query, Map<String, Object> context) throws InvalidQueryException, |
| QueryExecutionException { |
| if (context == null) { |
| context = Collections.emptyMap(); |
| } |
| String sRepoScope = (String) context.get(PROPERTY_REPOSITORYCONTEXT); |
| if (sRepoScope == null) { |
| sRepoScope = "*"; |
| } |
| |
| final String sFileScope = (String) context.get(PROPERTY_FILECONTEXT); |
| final List<String> filePatterns = new ArrayList<>(); |
| if (sFileScope == null) { |
| filePatterns.add("*"); |
| } else { |
| final String[] sFilePatterns = sFileScope.split(","); |
| for (String sFilePattern : sFilePatterns) { |
| filePatterns.add(sFilePattern); |
| } |
| } |
| |
| try { |
| final HawkQueryOptions opts = new HawkQueryOptions(); |
| if (context.containsKey(PROPERTY_DEFAULTNAMESPACES)) { |
| opts.setDefaultNamespaces((String) context.get(PROPERTY_DEFAULTNAMESPACES)); |
| } else { |
| opts.setDefaultNamespaces(defaultNamespaces); |
| } |
| opts.setRepositoryPattern(sRepoScope); |
| opts.setFilePatterns(filePatterns); |
| opts.setIncludeAttributes(true); |
| opts.setIncludeReferences(true); |
| opts.setIncludeNodeIDs(true); |
| opts.setIncludeContained(false); |
| |
| final String uuid = client.get().asyncQuery(name, query, language, opts); |
| if (context.containsKey(PROPERTY_CANCEL_CONSUMER)) { |
| @SuppressWarnings("unchecked") |
| java.util.function.Consumer<Runnable> consumer = (java.util.function.Consumer<Runnable>) context.get(PROPERTY_CANCEL_CONSUMER); |
| consumer.accept(() -> { |
| try { |
| client.get().cancelAsyncQuery(uuid); |
| } catch (TException e) { |
| LOGGER.error("Failed to cancel query " + uuid, e); |
| } |
| }); |
| } |
| QueryReport result = client.get().fetchAsyncQueryResults(uuid); |
| |
| return result; |
| } catch (UnknownQueryLanguage|InvalidQuery ex) { |
| throw new InvalidQueryException(ex); |
| } catch (FailedQuery ex) { |
| throw new QueryExecutionException(ex); |
| } catch (TException e) { |
| console.printerrln("Could not run contextful query"); |
| console.printerrln(e); |
| return e; |
| } |
| } |
| |
| @Override |
| public IAccessListener calculateDerivedAttributes(IModelIndexer m, |
| Iterable<IGraphNode> nodes) throws InvalidQueryException, |
| QueryExecutionException { |
| // this dummy query engine does *not* update derived attributes |
| // -- we're just a client. |
| return null; |
| } |
| |
| @Override |
| public void setDefaultNamespaces(String defaultNamespaces) { |
| this.defaultNamespaces = defaultNamespaces; |
| } |
| |
| @Override |
| public String getHumanReadableName() { |
| return "Thrift-based remote query engine"; |
| } |
| } |
| |
| /** |
| * Dummy implementation of {@link IVcsManager} that only provides the |
| * location and type and sends credential changes to the remote instance |
| * (does not retrieve remote username/password for security reasons). Only |
| * useful for the GUI when querying a remote Hawk instance using the Thrift |
| * API. |
| */ |
| private final class DummyVcsManager implements IVcsManager { |
| private final String location, type; |
| |
| private DummyVcsManager(String location, String type) { |
| this.location = location; |
| this.type = type; |
| } |
| |
| @Override |
| public File importFile(String revision, String path, File temp) { |
| // nothing to do |
| return null; |
| } |
| |
| @Override |
| public boolean isActive() { |
| return true; |
| } |
| |
| @Override |
| public void shutdown() { |
| // nothing to do |
| } |
| |
| @Override |
| public String getLocation() { |
| return location; |
| } |
| |
| @Override |
| public String getType() { |
| return type; |
| } |
| |
| @Override |
| public String getHumanReadableName() { |
| return location; |
| } |
| |
| @Override |
| public String getCurrentRevision() throws Exception { |
| return null; |
| } |
| |
| @Override |
| public List<VcsCommitItem> getDelta(String string) |
| throws Exception { |
| return null; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result |
| + ((location == null) ? 0 : location.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| DummyVcsManager other = (DummyVcsManager) obj; |
| if (location == null) { |
| if (other.location != null) |
| return false; |
| } else if (!location.equals(other.location)) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public boolean isAuthSupported() { |
| return true; |
| } |
| |
| @Override |
| public boolean isPathLocationAccepted() { |
| return true; |
| } |
| |
| @Override |
| public boolean isURLLocationAccepted() { |
| return true; |
| } |
| |
| @Override |
| public void setCredentials(String username, String password, ICredentialsStore credStore) { |
| try { |
| // Update both our local and remote copies of the credentials |
| credStore.put(location, |
| new ICredentialsStore.Credentials(username, password)); |
| client.get().updateRepositoryCredentials( |
| name, location, new Credentials(username, password)); |
| } catch (Exception e) { |
| console.printerrln(e); |
| } |
| } |
| |
| @Override |
| public String getFirstRevision() throws Exception { |
| return null; |
| } |
| |
| @Override |
| public VcsRepositoryDelta getDelta(String startRevision, String endRevision) throws Exception { |
| return null; |
| } |
| |
| @Override |
| public void init(String vcsloc, IModelIndexer indexer) throws Exception { |
| // nothing to do |
| } |
| |
| @Override |
| public void run() throws Exception { |
| // nothing to do |
| } |
| |
| @Override |
| public String getRepositoryPath(String rawPath) { |
| return rawPath; |
| } |
| |
| @Override |
| public String getUsername() { |
| try { |
| org.eclipse.hawk.core.ICredentialsStore.Credentials credentials = getCredentialsStore().get(location); |
| if (credentials != null) { |
| return credentials.getUsername(); |
| } |
| } catch (Exception e) { |
| LOGGER.error("Could not retrieve username from credentials store", e); |
| } |
| return null; |
| } |
| |
| @Override |
| public String getPassword() { |
| try { |
| org.eclipse.hawk.core.ICredentialsStore.Credentials credentials = getCredentialsStore().get(location); |
| if (credentials != null) { |
| return credentials.getPassword(); |
| } |
| } catch (Exception e) { |
| LOGGER.error("Could not retrieve password from credentials store", e); |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean isFrozen() { |
| try { |
| return client.get().isFrozen(name, location); |
| } catch (TException e) { |
| LOGGER.error(String.format( |
| "Could not retrieve frozen state of repository %s from remote Hawk %s", |
| name, location), e); |
| return false; |
| } |
| } |
| |
| @Override |
| public void setFrozen(boolean f) { |
| try { |
| client.get().setFrozen(name, location, f); |
| } catch (TException e) { |
| LOGGER.error(String.format( |
| "Could not change frozen state of repository %s of remote Hawk %s", |
| name, location), e); |
| } |
| } |
| |
| @Override |
| public String getDefaultLocation() { |
| return ""; |
| } |
| } |
| |
| private final String name, location; |
| private final ThriftRemoteHawkFactory factory; |
| private final ThreadLocal<Client> client; |
| private final IConsole console; |
| |
| /** Folder containing the Hawk properties.xml file. */ |
| private final File parentFolder; |
| private final ICredentialsStore credStore; |
| private String dbType; |
| |
| private final List<String> enabledPlugins; |
| |
| private final CompositeStateListener stateListener = new CompositeStateListener(); |
| private Consumer artemisConsumer; |
| |
| public ThriftRemoteModelIndexer(String name, String location, ThriftRemoteHawkFactory factory, File parentFolder, Supplier<Client> clientSupplier, |
| ICredentialsStore credStore, IConsole console, List<String> enabledPlugins) throws IOException { |
| this.name = name; |
| this.location = location; |
| this.factory = factory; |
| this.client = ThreadLocal.withInitial(clientSupplier); |
| this.credStore = credStore; |
| this.console = console; |
| this.parentFolder = parentFolder; |
| this.enabledPlugins = enabledPlugins; |
| |
| createDummyProperties(parentFolder); |
| |
| /* |
| * We subscribe to changes in the state of this indexer until it is |
| * deleted, if it exists already. If it doesn't exist yet, we'll try |
| * again after init invokes createInstance. |
| */ |
| connectToArtemis(); |
| } |
| |
| private void createDummyProperties(File parentFolder) throws IOException { |
| if (parentFolder.exists()) { |
| return; |
| } |
| |
| parentFolder.mkdirs(); |
| HawkProperties props = new HawkProperties(); |
| props.setDbType("dummy"); |
| props.setMonitoredVCS(new ArrayList<String[]>()); |
| |
| XStream stream = new XStream(new DomDriver()); |
| stream.processAnnotations(HawkProperties.class); |
| String out = stream.toXML(props); |
| try (BufferedWriter b = new BufferedWriter(new FileWriter( |
| getParentFolder() + File.separator + "properties.xml"))) { |
| b.write(out); |
| b.flush(); |
| } |
| } |
| |
| @Override |
| public void requestImmediateSync() throws Exception { |
| client.get().syncInstance(name, false); |
| } |
| |
| @Override |
| public void shutdown(ShutdownRequestType type) throws Exception { |
| if (type == ShutdownRequestType.ALWAYS) { |
| // for remote instances, we only honour explicit requests by users. |
| client.get().stopInstance(name); |
| } |
| artemisConsumer.closeSession(); |
| } |
| |
| @Override |
| public void delete() throws Exception { |
| client.get().removeInstance(name); |
| artemisConsumer.closeSession(); |
| } |
| |
| @Override |
| public IGraphDatabase getGraph() { |
| console.printerrln("Graph is not accessible for " + ThriftRemoteHawk.class.getName()); |
| return null; |
| } |
| |
| @Override |
| public Set<IVcsManager> getRunningVCSManagers() { |
| try { |
| List<Repository> repositories = client.get().listRepositories(name); |
| Set<IVcsManager> dummies = new HashSet<>(); |
| for (final Repository repo : repositories) { |
| dummies.add(new DummyVcsManager(repo.uri, repo.type)); |
| } |
| return dummies; |
| } catch (TException e) { |
| console.printerrln(e); |
| return Collections.emptySet(); |
| } |
| } |
| |
| @Override |
| public Set<String> getKnownMMUris() { |
| try { |
| return new HashSet<>(client.get().listMetamodels(name)); |
| } catch (TException e) { |
| console.printerrln(e); |
| return Collections.emptySet(); |
| } |
| } |
| |
| @Override |
| public String getId() { |
| return name; |
| } |
| |
| @Override |
| public void registerMetamodels(File... files) throws Exception { |
| List<org.eclipse.hawk.service.api.File> thriftFiles = new ArrayList<>(); |
| for (File f : files) { |
| thriftFiles.add(APIUtils.convertJavaFileToThriftFile(f)); |
| } |
| client.get().registerMetamodels(name, thriftFiles); |
| } |
| |
| @Override |
| public IConsole getConsole() { |
| return console; |
| } |
| |
| @Override |
| public void addVCSManager(IVcsManager vcs, boolean persist) { |
| try { |
| org.eclipse.hawk.core.ICredentialsStore.Credentials storedCredentials = getCredentialsStore().get(vcs.getLocation()); |
| |
| Credentials credentials = null; |
| if (storedCredentials != null) { |
| credentials = new Credentials(); |
| credentials.setUsername(storedCredentials.getUsername()); |
| credentials.setPassword(storedCredentials.getPassword()); |
| } |
| |
| final Repository repo = new Repository(vcs.getLocation(), vcs.getType()); |
| repo.setIsFrozen(false); |
| client.get().addRepository(name, repo, credentials); |
| } catch (Exception e) { |
| console.printerrln("Could not add the specified repository"); |
| console.printerrln(e); |
| } |
| } |
| |
| @Override |
| public void addModelUpdater(IModelUpdater updater) { |
| console.printerrln("Cannot add model updaters to " + this.getClass().getName()); |
| } |
| |
| @Override |
| public void addMetaModelResourceFactory(IMetaModelResourceFactory metaModelParser) { |
| console.printerrln("Cannot add metamodel resource factories to " + this.getClass().getName()); |
| } |
| |
| @Override |
| public void addModelResourceFactory(IModelResourceFactory modelParser) { |
| console.printerrln("Cannot add model resource factories to " + this.getClass().getName()); |
| } |
| |
| @Override |
| public void setDB(IGraphDatabase db, boolean persist) { |
| setDBType(db.getClass().getCanonicalName()); |
| } |
| |
| @Override |
| public void addQueryEngine(IQueryEngine q) { |
| console.printerrln("Cannot add query engines to " + this.getClass().getName()); |
| } |
| |
| @Override |
| public void init(int minDelay, int maxDelay) throws Exception { |
| try { |
| client.get().startInstance(name); |
| } catch (HawkInstanceNotFound ex) { |
| final String factoryName = factory.getFactoryName(); |
| client.get().createInstance(name, dbType, minDelay, maxDelay, enabledPlugins, factoryName); |
| } |
| connectToArtemis(); |
| } |
| |
| protected void connectToArtemis() { |
| try { |
| HawkState currentState = HawkState.RUNNING; |
| String currentInfo = ""; |
| for (HawkInstance instance : client.get().listInstances()) { |
| if (name.equals(instance.getName())) { |
| currentState = instance.getState(); |
| currentInfo = instance.getMessage(); |
| } |
| } |
| |
| org.eclipse.hawk.core.ICredentialsStore.Credentials creds = HManager.getInstance().getCredentialsStore().get(location); |
| if (artemisConsumer == null) { |
| Subscription subState = client.get().watchStateChanges(name); |
| artemisConsumer = APIUtils.connectToArtemis(subState, SubscriptionDurability.TEMPORARY); |
| } |
| if (!artemisConsumer.isSessionOpen()) { |
| if (creds != null) { |
| artemisConsumer.openSession(creds.getUsername(), creds.getPassword()); |
| } else { |
| artemisConsumer.openSession(null, null); |
| } |
| artemisConsumer.processChangesAsync(new StatePropagationConsumer(currentState, currentInfo)); |
| } |
| } catch (HawkInstanceNotFound nf) { |
| /* |
| * Not found yet: this is probably because of a call from the |
| * constructor right before invoking init. This is normal: we |
| * will simply try again once init has invoked createInstance. |
| */ |
| } catch (Exception e) { |
| Activator.logError(e); |
| } |
| } |
| |
| @Override |
| public Collection<IModelResourceFactory> getModelParsers() { |
| LOGGER.warn("Cannot access model parsers in {}", this.getClass().getName()); |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public Collection<IMetaModelResourceFactory> getMetaModelParsers() { |
| LOGGER.warn("Cannot access metamodel parsers in {}", this.getClass().getName()); |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public IMetaModelResourceFactory getMetaModelParser(String metaModelType) { |
| LOGGER.warn("Cannot access metamodel parsers in {}", this.getClass().getName()); |
| return null; |
| } |
| |
| @Override |
| public Map<String, IQueryEngine> getKnownQueryLanguages() { |
| try { |
| final Map<String, IQueryEngine> dummyMap = new HashMap<>(); |
| for (final String language : client.get().listQueryLanguages(name)) { |
| dummyMap.put(language, new RemoteQueryEngine(language)); |
| } |
| return dummyMap; |
| } catch (TException e) { |
| console.printerrln("Could not retrieve the known query languages"); |
| console.printerrln(e); |
| return Collections.emptyMap(); |
| } |
| } |
| |
| @Override |
| public File getParentFolder() { |
| return parentFolder; |
| } |
| |
| @Override |
| public IMetaModelUpdater getMetaModelUpdater() { |
| console.printerrln("Cannot check the metamodel updater in " + this.getClass().getName()); |
| return null; |
| } |
| |
| @Override |
| public void setMetaModelUpdater(IMetaModelUpdater metaModelUpdater) { |
| console.printerrln("Cannot change the metamodel updater in " + this.getClass().getName()); |
| } |
| |
| @Override |
| public void addDerivedAttribute(String metamodeluri, String typename, |
| String attributename, String attributetype, boolean isMany, |
| boolean isOrdered, boolean isUnique, String derivationlanguage, |
| String derivationlogic) { |
| DerivedAttributeSpec spec = new DerivedAttributeSpec(); |
| spec.setMetamodelUri(metamodeluri); |
| spec.setTypeName(typename); |
| spec.setAttributeName(attributename); |
| spec.setAttributeType(attributetype); |
| spec.setIsMany(isMany); |
| spec.setIsOrdered(isOrdered); |
| spec.setIsUnique(isUnique); |
| spec.setDerivationLanguage(derivationlanguage); |
| spec.setDerivationLogic(derivationlogic); |
| |
| try { |
| client.get().addDerivedAttribute(name, spec); |
| } catch (TException e) { |
| console.printerrln("Could not add derived attribute"); |
| console.printerrln(e); |
| } |
| } |
| |
| @Override |
| public void addIndexedAttribute(String metamodeluri, String typename, String attributename) { |
| IndexedAttributeSpec spec = new IndexedAttributeSpec(); |
| spec.setMetamodelUri(metamodeluri); |
| spec.setTypeName(typename); |
| spec.setAttributeName(attributename); |
| |
| try { |
| client.get().addIndexedAttribute(name, spec); |
| } catch (TException e) { |
| console.printerrln("Could not add indexed attribute"); |
| console.printerrln(e); |
| } |
| } |
| |
| @Override |
| public Collection<IndexedAttributeParameters> getDerivedAttributes() { |
| final List<IndexedAttributeParameters> attrs = new ArrayList<>(); |
| try { |
| for (DerivedAttributeSpec spec : client.get().listDerivedAttributes(name)) { |
| DerivedAttributeParameters params = new DerivedAttributeParameters( |
| spec.metamodelUri, spec.typeName, spec.attributeName, |
| spec.attributeType, spec.isMany, spec.isOrdered, |
| spec.isUnique, spec.derivationLanguage, spec.derivationLogic |
| ); |
| attrs.add(params); |
| } |
| } catch (TException e) { |
| console.printerrln("Could not list the derived attributes"); |
| console.printerrln(e); |
| } |
| return attrs; |
| } |
| |
| @Override |
| public Collection<IndexedAttributeParameters> getIndexedAttributes() { |
| final List<IndexedAttributeParameters> attrs = new ArrayList<>(); |
| try { |
| for (IndexedAttributeSpec spec : client.get().listIndexedAttributes(name)) { |
| IndexedAttributeParameters params = new IndexedAttributeParameters( |
| spec.metamodelUri, spec.typeName, spec.attributeName |
| ); |
| attrs.add(params); |
| } |
| } catch (TException e) { |
| console.printerrln("Could not list the derived attributes"); |
| console.printerrln(e); |
| } |
| return attrs; |
| } |
| |
| @Override |
| public Collection<String> getIndexes() { |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public List<String> validateExpression(String derivationlanguage, String derivationlogic) { |
| return getKnownQueryLanguages().get(derivationlanguage).validate(derivationlogic); |
| } |
| |
| @Override |
| public String getName() { |
| return name; |
| } |
| |
| @Override |
| public boolean isRunning() { |
| connectToArtemis(); |
| try { |
| for (HawkInstance instance : client.get().listInstances()) { |
| if (instance.name.equals(name)) { |
| return instance.state != HawkState.STOPPED; |
| } |
| } |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean addGraphChangeListener(IGraphChangeListener changeListener) { |
| // TODO Add remote notifications here? |
| return false; |
| } |
| |
| @Override |
| public boolean removeGraphChangeListener(IGraphChangeListener changeListener) { |
| // TODO Add remote notifications here? |
| return false; |
| } |
| |
| @Override |
| public CompositeGraphChangeListener getCompositeGraphChangeListener() { |
| // TODO Add remote notifications here? |
| return null; |
| } |
| |
| @Override |
| public void setSyncMetricsEnabled(Boolean enable) { |
| // do nothing |
| } |
| |
| @Override |
| public void removeMetamodels(String... metamodelURIs) throws Exception { |
| client.get().unregisterMetamodels(name, Arrays.asList(metamodelURIs)); |
| } |
| |
| @Override |
| public ICredentialsStore getCredentialsStore() { |
| return credStore; |
| } |
| |
| public String getDBType() { |
| return dbType; |
| } |
| |
| public void setDBType(String dbtype) { |
| this.dbType = dbtype; |
| } |
| |
| @Override |
| public boolean addStateListener(IStateListener l) { |
| return stateListener.add(l); |
| } |
| |
| @Override |
| public boolean removeStateListener(IStateListener l) { |
| return stateListener.remove(l); |
| } |
| |
| @Override |
| public CompositeStateListener getCompositeStateListener() { |
| return stateListener; |
| } |
| |
| @Override |
| public String getDerivedAttributeExecutionEngine() { |
| return null; |
| } |
| |
| @Override |
| public void removeVCSManager(IVcsManager vcs) throws Exception { |
| client.get().removeRepository(name, vcs.getLocation()); |
| } |
| |
| @Override |
| public void setPolling(int base, int max) { |
| try { |
| client.get().configurePolling(name, base, max); |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| } |
| } |
| |
| @Override |
| public boolean removeIndexedAttribute(String metamodelUri, String typename, String attributename) { |
| IndexedAttributeSpec spec = new IndexedAttributeSpec(); |
| spec.setMetamodelUri(metamodelUri); |
| spec.setTypeName(typename); |
| spec.setAttributeName(attributename); |
| try { |
| client.get().removeIndexedAttribute(name, spec); |
| return true; |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return false; |
| } |
| } |
| |
| @Override |
| public boolean removeDerivedAttribute(String metamodelUri, String typeName, String attributeName) { |
| DerivedAttributeSpec spec = new DerivedAttributeSpec(); |
| spec.setMetamodelUri(metamodelUri); |
| spec.setTypeName(typeName); |
| spec.setAttributeName(attributeName); |
| try { |
| client.get().removeDerivedAttribute(name, spec); |
| return true; |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return false; |
| } |
| } |
| |
| @Override |
| public void waitFor(IStateListener.HawkState targetState) throws InterruptedException { |
| waitFor(targetState, 0); |
| } |
| |
| @Override |
| public void waitFor(IStateListener.HawkState targetState, long timeoutMillis) throws InterruptedException { |
| synchronized (stateListener) { |
| final long end = System.currentTimeMillis() + timeoutMillis; |
| for (IStateListener.HawkState s = stateListener.getCurrentState(); s != targetState; s = stateListener.getCurrentState()) { |
| if (s == IStateListener.HawkState.STOPPED) { |
| throw new IllegalStateException("The selected Hawk is stopped"); |
| } |
| |
| if (timeoutMillis == 0) { |
| stateListener.wait(); |
| } else { |
| final long remaining = end - System.currentTimeMillis(); |
| if (remaining > 0) { |
| // Wait for the remaining time |
| stateListener.wait(remaining); |
| } else { |
| // Exit the loop due to timeout |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public <T> ScheduledFuture<T> scheduleTask(Callable<T> task, long delayMillis) { |
| // TODO If this works to fix server configuration issues, |
| // reevaluate. |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Set<String> getKnownMetamodelFileExtensions() { |
| try { |
| List<MetamodelParserDetails> details = client.get().listMetamodelParsers(name); |
| Set<String> extensions = new HashSet<>(); |
| for (MetamodelParserDetails e : details) { |
| extensions.addAll(e.getFileExtensions()); |
| } |
| return extensions; |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return Collections.emptySet(); |
| } |
| } |
| |
| @Override |
| public Set<String> getKnownMetaModelParserTypes() { |
| try { |
| List<MetamodelParserDetails> details = client.get().listMetamodelParsers(name); |
| Set<String> types = new HashSet<>(); |
| for (MetamodelParserDetails e : details) { |
| types.add(e.getIdentifier()); |
| } |
| return types; |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return Collections.emptySet(); |
| } |
| } |
| |
| @Override |
| public List<IModelUpdater> getModelUpdaters() { |
| console.printerrln("Cannot access updaters in " + this.getClass().getName()); |
| return null; |
| } |
| |
| @Override |
| public List<String> getMetamodels() { |
| try { |
| return client.get().listMetamodels(name); |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return Collections.emptyList(); |
| } |
| } |
| |
| @Override |
| public List<String> getTypes(String metamodelURI) throws NoSuchElementException { |
| try { |
| return client.get().listTypeNames(name, metamodelURI); |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return Collections.emptyList(); |
| } |
| } |
| |
| @Override |
| public List<String> getAttributes(String metamodelURI, String typeName) throws NoSuchElementException { |
| try { |
| return client.get().listAttributeNames(name, metamodelURI, typeName); |
| } catch (TException e) { |
| LOGGER.error(e.getMessage(), e); |
| return Collections.emptyList(); |
| } |
| } |
| |
| @Override |
| public void removeMetaModelResourceFactory(IMetaModelResourceFactory metaModelParser) { |
| console.printerrln("Cannot remove metamodel resource factories to " + this.getClass().getName()); |
| } |
| |
| @Override |
| public void removeModelResourceFactory(IModelResourceFactory modelParser) { |
| console.printerrln("Cannot remove model resource factories to " + this.getClass().getName()); |
| |
| } |
| |
| @Override |
| public void removeModelUpdater(IModelUpdater updater) throws Exception { |
| console.printerrln("Cannot remove model updaters to " + this.getClass().getName()); |
| |
| } |
| |
| } |