<commit_before>/*******************************************************************************
 * Copyright (c) 2015 University of York.
 * 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:
 *    <NAME> - initial API and implementation
 *******************************************************************************/
package uk.ac.york.mondo.integration.hawk.emf;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import net.sf.cglib.proxy.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;

import org.apache.activemq.artemis.api.core.ActiveMQException;
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.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.DynamicEObjectImpl;
import org.eclipse.emf.ecore.impl.DynamicEStoreEObjectImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.ac.york.mondo.integration.api.AttributeSlot;
import uk.ac.york.mondo.integration.api.ContainerSlot;
import uk.ac.york.mondo.integration.api.Hawk.Client;
import uk.ac.york.mondo.integration.api.HawkAttributeRemovalEvent;
import uk.ac.york.mondo.integration.api.HawkAttributeUpdateEvent;
import uk.ac.york.mondo.integration.api.HawkChangeEvent;
import uk.ac.york.mondo.integration.api.HawkInstanceNotFound;
import uk.ac.york.mondo.integration.api.HawkInstanceNotRunning;
import uk.ac.york.mondo.integration.api.HawkModelElementAdditionEvent;
import uk.ac.york.mondo.integration.api.HawkModelElementRemovalEvent;
import uk.ac.york.mondo.integration.api.HawkReferenceAdditionEvent;
import uk.ac.york.mondo.integration.api.HawkReferenceRemovalEvent;
import uk.ac.york.mondo.integration.api.MixedReference;
import uk.ac.york.mondo.integration.api.ModelElement;
import uk.ac.york.mondo.integration.api.ReferenceSlot;
import uk.ac.york.mondo.integration.api.Subscription;
import uk.ac.york.mondo.integration.api.SubscriptionDurability;
import uk.ac.york.mondo.integration.api.utils.APIUtils;
import uk.ac.york.mondo.integration.api.utils.ActiveMQBufferTransport;
import uk.ac.york.mondo.integration.artemis.consumer.Consumer;
import uk.ac.york.mondo.integration.hawk.emf.HawkModelDescriptor.LoadingMode;

/**
 * EMF driver that reads a remote model from a Hawk index.
 */
public class HawkResourceImpl extends ResourceImpl {

	private final class ModelSubscriberHandler implements MessageHandler {
		@Override
		public void onMessage(ClientMessage message) {
			try {
				final TProtocol proto = new TCompactProtocol(new ActiveMQBufferTransport(message.getBodyBuffer()));
				final HawkChangeEvent change = new HawkChangeEvent();
				try {
					change.read(proto);
					LOGGER.debug("Received message from Artemis: {}", change);

					if (change.isSetModelElementAttributeUpdate()) {
						handle(change.getModelElementAttributeUpdate());
					}
					else if (change.isSetModelElementAttributeRemoval()) {
						handle(change.getModelElementAttributeRemoval());
					}
					else if (change.isSetModelElementAddition()) {
						handle(change.getModelElementAddition());
					}
					else if (change.isSetModelElementRemoval()) {
						handle(change.getModelElementRemoval());
					}
					else if (change.isSetReferenceAddition()) {
						handle(change.getReferenceAddition());
					}
					else if (change.isSetReferenceRemoval()) {
						handle(change.getReferenceRemoval());
					}
				} catch (TException | IOException e) {
					LOGGER.error("Error while decoding incoming message", e);
				}

				message.acknowledge();
			} catch (ActiveMQException e) {
				LOGGER.error("Failed to ack message", e);
			}
		}

		@SuppressWarnings("unchecked")
		protected void handle(final HawkReferenceRemovalEvent ev) {
			final EObject source = nodeIdToEObjectMap.get(ev.sourceId);
			final EObject target = nodeIdToEObjectMap.get(ev.targetId);
			if (source != null && target != null) {
				final EReference ref = (EReference)source.eClass().getEStructuralFeature(ev.refName);
				if (ref.isMany()) {
					Collection<EObject> objs = (Collection<EObject>)source.eGet(ref);
					objs.remove(target);
				} else {
					source.eUnset(ref);
				}
			}
		}

		@SuppressWarnings("unchecked")
		protected void handle(final HawkReferenceAdditionEvent ev) {
			final EObject source = nodeIdToEObjectMap.get(ev.sourceId);
			final EObject target = nodeIdToEObjectMap.get(ev.targetId);
			if (source != null && target != null) {
				final EReference ref = (EReference)source.eClass().getEStructuralFeature(ev.refName);
				if (ref.isMany()) {
					Collection<EObject> objs = (Collection<EObject>)source.eGet(ref);
					objs.add(target);
				} else {
					source.eSet(ref, target);
				}

				if (ref.isContainer()) {
					getContents().remove(source);
				}
			}
		}

		@SuppressWarnings("unchecked")
		protected void handle(final HawkModelElementRemovalEvent ev) {
			final EObject eob = nodeIdToEObjectMap.remove(ev.id);
			if (eob != null) {
				getContents().remove(eob);

				final EObject container = eob.eContainer();
				if (container != null) {
					if (eob.eContainmentFeature() != null) {
						eob.eUnset(eob.eContainmentFeature());
					}

					final EStructuralFeature containingFeature = eob.eContainingFeature();
					if (containingFeature.isMany()) {
						((Collection<EObject>)container.eGet(containingFeature)).remove(eob);
					} else {
						container.eUnset(containingFeature);
					}
				}
			}
		}

		protected void handle(final HawkModelElementAdditionEvent ev) {
			final Registry registry = getResourceSet().getPackageRegistry();
			final EClass eClass = getEClass(ev.metamodelURI, ev.typeName, registry);
			final EFactory factory = registry.getEFactory(ev.metamodelURI);

			final EObject eob = factory.create(eClass);
			nodeIdToEObjectMap.put(ev.id, eob);
			getContents().add(eob);
		}

		protected void handle(final HawkAttributeRemovalEvent ev) {
			final EObject eob = nodeIdToEObjectMap.get(ev.getId());
			if (eob != null) {
				final EStructuralFeature eAttr = eob.eClass().getEStructuralFeature(ev.attribute);
				if (eAttr != null) {
					eob.eUnset(eAttr);
				}<commit_msg>HawkResourceImpl: protect against duplicate 'new element' events and fix bug with protocols != compact<commit_after>/*******************************************************************************
 * Copyright (c) 2015 University of York.
 * 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:
 *    <NAME> - initial API and implementation
 *******************************************************************************/
package uk.ac.york.mondo.integration.hawk.emf;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import net.sf.cglib.proxy.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;

import org.apache.activemq.artemis.api.core.ActiveMQException;
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.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.DynamicEObjectImpl;
import org.eclipse.emf.ecore.impl.DynamicEStoreEObjectImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.ac.york.mondo.integration.api.AttributeSlot;
import uk.ac.york.mondo.integration.api.ContainerSlot;
import uk.ac.york.mondo.integration.api.Hawk.Client;
import uk.ac.york.mondo.integration.api.HawkAttributeRemovalEvent;
import uk.ac.york.mondo.integration.api.HawkAttributeUpdateEvent;
import uk.ac.york.mondo.integration.api.HawkChangeEvent;
import uk.ac.york.mondo.integration.api.HawkInstanceNotFound;
import uk.ac.york.mondo.integration.api.HawkInstanceNotRunning;
import uk.ac.york.mondo.integration.api.HawkModelElementAdditionEvent;
import uk.ac.york.mondo.integration.api.HawkModelElementRemovalEvent;
import uk.ac.york.mondo.integration.api.HawkReferenceAdditionEvent;
import uk.ac.york.mondo.integration.api.HawkReferenceRemovalEvent;
import uk.ac.york.mondo.integration.api.MixedReference;
import uk.ac.york.mondo.integration.api.ModelElement;
import uk.ac.york.mondo.integration.api.ReferenceSlot;
import uk.ac.york.mondo.integration.api.Subscription;
import uk.ac.york.mondo.integration.api.SubscriptionDurability;
import uk.ac.york.mondo.integration.api.utils.APIUtils;
import uk.ac.york.mondo.integration.api.utils.ActiveMQBufferTransport;
import uk.ac.york.mondo.integration.artemis.consumer.Consumer;
import uk.ac.york.mondo.integration.hawk.emf.HawkModelDescriptor.LoadingMode;

/**
 * EMF driver that reads a remote model from a Hawk index.
 */
public class HawkResourceImpl extends ResourceImpl {

	private final class ModelSubscriberHandler implements MessageHandler {
		@Override
		public void onMessage(ClientMessage message) {
			try {
				final TProtocolFactory protocolFactory = descriptor.getThriftProtocol().getProtocolFactory();
				final TProtocol proto = protocolFactory.getProtocol(new ActiveMQBufferTransport(message.getBodyBuffer()));
				final HawkChangeEvent change = new HawkChangeEvent();
				try {
					change.read(proto);
					LOGGER.debug("Received message from Artemis: {}", change);

					if (change.isSetModelElementAttributeUpdate()) {
						handle(change.getModelElementAttributeUpdate());
					}
					else if (change.isSetModelElementAttributeRemoval()) {
						handle(change.getModelElementAttributeRemoval());
					}
					else if (change.isSetModelElementAddition()) {
						handle(change.getModelElementAddition());
					}
					else if (change.isSetModelElementRemoval()) {
						handle(change.getModelElementRemoval());
					}
					else if (change.isSetReferenceAddition()) {
						handle(change.getReferenceAddition());
					}
					else if (change.isSetReferenceRemoval()) {
						handle(change.getReferenceRemoval());
					}
				} catch (TException | IOException e) {
					LOGGER.error("Error while decoding incoming message", e);
				}

				message.acknowledge();
			} catch (ActiveMQException e) {
				LOGGER.error("Failed to ack message", e);
			}
		}

		@SuppressWarnings("unchecked")
		protected void handle(final HawkReferenceRemovalEvent ev) {
			final EObject source = nodeIdToEObjectMap.get(ev.sourceId);
			final EObject target = nodeIdToEObjectMap.get(ev.targetId);
			if (source != null && target != null) {
				final EReference ref = (EReference)source.eClass().getEStructuralFeature(ev.refName);
				if (ref.isMany()) {
					Collection<EObject> objs = (Collection<EObject>)source.eGet(ref);
					objs.remove(target);
				} else {
					source.eUnset(ref);
				}
			}
		}

		@SuppressWarnings("unchecked")
		protected void handle(final HawkReferenceAdditionEvent ev) {
			final EObject source = nodeIdToEObjectMap.get(ev.sourceId);
			final EObject target = nodeIdToEObjectMap.get(ev.targetId);
			if (source != null && target != null) {
				final EReference ref = (EReference)source.eClass().getEStructuralFeature(ev.refName);
				if (ref.isMany()) {
					Collection<EObject> objs = (Collection<EObject>)source.eGet(ref);
					objs.add(target);
				} else {
					source.eSet(ref, target);
				}

				if (ref.isContainer()) {
					getContents().remove(source);
				}
			}
		}

		@SuppressWarnings("unchecked")
		protected void handle(final HawkModelElementRemovalEvent ev) {
			final EObject eob = nodeIdToEObjectMap.remove(ev.id);
			if (eob != null) {
				getContents().remove(eob);

				final EObject container = eob.eContainer();
				if (container != null) {
					if (eob.eContainmentFeature() != null) {
						eob.eUnset(eob.eContainmentFeature());
					}

					final EStructuralFeature containingFeature = eob.eContainingFeature();
					if (containingFeature.isMany()) {
						((Collection<EObject>)container.eGet(containingFeature)).remove(eob);
					} else {
						container.eUnset(containingFeature);
					}
				}
			}
		}

		protected void handle(final HawkModelElementAdditionEvent ev) {
			final Registry registry = getResourceSet().getPackageRegistry();
			final EClass eClass = getEClass(ev.metamodelURI, ev.typeName, registry);
			final EFactory factory = registry.getEFactory(ev.metamodelURI);

			if (!nodeIdToEObjectMap.containsKey(ev.id)) {
				final EObject eob = factory.create(eClass);
				nodeIdToEObjectMap.put(ev.id, eob);
				getContents().add(eob);
			}
		}

		protected void handle(final HawkAttributeRemovalEvent ev) {
			final EObject eob = nodeIdToEObjectMap.get(ev.getId());
			if (eob != null) {
				final EStructuralFeature eAttr = eob.eClass().getEStructuralFeature(ev.attribute);
				if (eAttr != null) {
					eob.eUnset(eAttr);
				}
{'fraction_non_alphanumeric': 0.1351909872675155, 'fraction_numerical': 0.0013332444503699754, 'mean_word_length': 4.691198786039454, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2659490', 'n_tokens_mistral': 5395, 'n_tokens_neox': 4661, 'n_words': 817}