All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.fraunhofer.iese.ind2uce.reactive.AbstractRxPEP Maven / Gradle / Ivy

/*-
 * =================================LICENSE_START=================================
 * IND2UCE
 * %%
 * Copyright (C) 2017 Fraunhofer IESE (www.iese.fraunhofer.de)
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =================================LICENSE_END=================================
 */

package de.fraunhofer.iese.ind2uce.reactive;

import de.fraunhofer.iese.ind2uce.api.component.interfaces.IPolicyEnforcementPoint;
import de.fraunhofer.iese.ind2uce.api.policy.Event;
import de.fraunhofer.iese.ind2uce.api.policy.identifier.ActionId;
import de.fraunhofer.iese.ind2uce.api.policy.parameter.ParameterList;
import de.fraunhofer.iese.ind2uce.logger.LoggerFactory;
import de.fraunhofer.iese.ind2uce.pep.PolicyEnforcementPoint;
import de.fraunhofer.iese.ind2uce.reactive.common.EventParameter;
import de.fraunhofer.iese.ind2uce.reactive.common.EventSpecification;
import de.fraunhofer.iese.ind2uce.reactive.common.EventUUID;
import de.fraunhofer.iese.ind2uce.reactive.common.IncorrectPEPDescriptionError;
import de.fraunhofer.iese.ind2uce.reactive.common.RxPEP;
import de.fraunhofer.iese.ind2uce.reactive.common.RxPEPState;

import org.slf4j.Logger;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicReference;

import rx.Observable;
import rx.schedulers.Schedulers;

/**
 * Base Implementation of a RxPEP.
 */
public abstract class AbstractRxPEP implements RxPEP {

  protected static Logger LOG = LoggerFactory.getLogger(PolicyEnforcementPoint.class);

  /**
   * The pep state.
   */
  protected final AtomicReference pepState = new AtomicReference<>(RxPEPState.REGISTRATION_NOT_STARTED);

  /**
   * The policy enforcement point.
   */
  protected final IPolicyEnforcementPoint policyEnforcementPoint;

  /**
   * The documentation API.
   */
  protected final Class pepInterfaceDescription;

  /**
   * Instantiates a new Rx PEP.
   *
   * @param pepInterfaceDescription the documentation API
   * @param policyEnforcementPoint the policy enforcement point
   */
  public AbstractRxPEP(IPolicyEnforcementPoint policyEnforcementPoint, Class pepInterfaceDescription) {
    this.policyEnforcementPoint = policyEnforcementPoint;
    this.pepInterfaceDescription = pepInterfaceDescription;
  }

  /*
   * (non-Javadoc)
   * @see de.fraunhofer.iese.ind2uce.reactive.common.RxPEP#createInstanceAPI()
   */
  @Override
  @SuppressWarnings("unchecked")
  public T createInstanceAPI() {
    if (this.pepState.get() == RxPEPState.REGISTRATION_DONE_SUCCESSFULLY) {
      return (T)Proxy.newProxyInstance(this.pepInterfaceDescription.getClassLoader(), new Class[] {
          this.pepInterfaceDescription
      }, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

          // pass to object class if method belongs to Object class
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          return AbstractRxPEP.this.enforceDecision(method, args);

        }
      });
    }
    throw new IllegalStateException("RxPEP is not registered yet, please perform successful registration before using documentation API");
  }

  /*
   * (non-Javadoc)
   * @see de.fraunhofer.iese.ind2uce.reactive.common.RxPEP#doRegisterAtPMP()
   */
  @Override
  public Observable doRegisterAtPMP() {
    return Observable.fromCallable(() -> {
      switch (this.pepState.get()) {
        case REGISTRATION_DONE_SUCCESSFULLY:
          return false;
        case REGISTRATION_FAILED:
          return false;
        case REGISTRATION_NOT_STARTED:
          this.pepState.set(RxPEPState.REGISTRATION_UNDER_PROCESS);
          return this.policyEnforcementPoint.initialize();
        case REGISTRATION_UNDER_PROCESS:
          throw new IllegalStateException("PEP under registration, don't try to register when it's already under the process");
        default:
          throw new IllegalStateException("WTF state");
      }
    }).doOnError((e) -> {
      if (e instanceof IOException) {
        LOG.error("Registration of PEP at PMP failed!");
        this.pepState.set(RxPEPState.REGISTRATION_FAILED);
      }
    }).doOnNext(aBoolean -> {
      if (this.pepState.get() != RxPEPState.REGISTRATION_DONE_SUCCESSFULLY) {
        if (aBoolean) {
          this.pepState.set(RxPEPState.REGISTRATION_DONE_SUCCESSFULLY);
          this.postSuccessfulRegistration();
        } else {
          this.pepState.set(RxPEPState.REGISTRATION_FAILED);
        }
      }
    }).subscribeOn(Schedulers.immediate());
  }

  protected abstract Object enforceDecision(Method method, Object[] args);

  /**
   * Returns the parameter of type PEPParamKey.
   *
   * @param annotations the annotations
   * @return the parameter annotation
   */
  EventParameter getParameterAnnotation(Annotation[] annotations) {
    for (final Annotation annotation : annotations) {
      if (annotation instanceof EventParameter) {
        return (EventParameter)annotation;
      }
    }
    return null;
  }

  /*
   * (non-Javadoc)
   * @see
   * de.fraunhofer.iese.ind2uce.reactive.common.RxPEP#getPolicyEnforcementPoint(
   * )
   */
  @Override
  public IPolicyEnforcementPoint getPolicyEnforcementPoint() {
    return this.policyEnforcementPoint;
  }

  /*
   * (non-Javadoc)
   * @see de.fraunhofer.iese.ind2uce.reactive.common.RxPEP#isReady()
   */
  @Override
  public RxPEPState isReady() {
    return this.pepState.get();
  }

  protected abstract void postSuccessfulRegistration();

  /**
   * Gets the action id from the given method and creates a new event with
   * specific UUID and parameters set.
   *
   * @param method the method
   * @param methodArguments the method arguments
   * @return the event
   * @throws IncorrectPEPDescriptionError the incorrect PEP description error
   */
  protected Event readAndCreateEvent(Method method, Object[] methodArguments) throws IncorrectPEPDescriptionError {
    Event event;
    final ActionId actionId = this.readEventDescription(method);
    event = new Event(actionId);
    event.setTag(this.readUUID(method, methodArguments));
    event.setParameters(this.readParameterList(method.getParameterTypes(), method.getParameterAnnotations(), methodArguments));
    return event;
  }

  /**
   * Gets the platform, context and action values from the event specification
   * of the given method and creates the action id and returns it.
   *
   * @param method the method
   * @return the action id
   */
  protected ActionId readEventDescription(Method method) {
    final Annotation[] methodAnnotation = method.getDeclaredAnnotationsByType(EventSpecification.class);
    if (methodAnnotation.length > 0) {
      ActionId eventId = null;
      final EventSpecification ed = ((EventSpecification)methodAnnotation[0]);
      eventId = new ActionId(ed.scope(), ed.action());
      return eventId;
    }
    LOG.error("API declaration error: ActionId can't be null for event.");
    throw new IncorrectPEPDescriptionError("ActionId can't be null for event. API declaration error");
  }

  /**
   * Returns the annotations of type PEPParamKey with their corresponding method
   * argument.
   *
   * @param parametersType parameter type
   * @param parametersAnnotations the parameters annotations
   * @param methodArguments the method arguments
   * @return the parameter list
   */
  protected ParameterList readParameterList(Class[] parametersType, Annotation[][] parametersAnnotations, Object[] methodArguments) {
    final ParameterList parameters = new ParameterList();
    for (int i = 0; i < parametersAnnotations.length; i++) {
      final EventParameter PEPParamKey = this.getParameterAnnotation(parametersAnnotations[i]);
      if (PEPParamKey != null) {
        parameters.addParameter(PEPParamKey.name(), methodArguments[i], parametersType[i]);
      }
    }
    return parameters;
  }

  /**
   * Returns the corresponding argument to the UUID of the given method.
   *
   * @param method the method
   * @param methodArguments the method arguments
   * @return the UUID
   */
  private Object readUUID(final Method method, final Object[] methodArguments) {
    final Parameter parameters[] = method.getParameters();
    for (int i = 0; i < parameters.length; i++) {
      if (parameters[i].getAnnotationsByType(EventUUID.class).length != 0) {
        return methodArguments[i];
      }
    }
    return null;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy