Exemplo n.º 1
0
/**
 * The class <strong>WaveBase</strong>.
 *
 * <p>This Bean is used to move wave's data through layer. It allow to manage priorities.
 */
public class WaveBase implements Wave, LinkMessages {

  /** The class logger. */
  private static final JRLogger LOGGER = JRLoggerFactory.getLogger(WaveBase.class);

  /** The space separator. */
  private static final String SPACE_SEP = " ";

  /** The Wave Unique Identifier. */
  private final String wuid;

  /** The Wave timestamp. */
  private final long timestamp;

  /** The wave status (can be bound). */
  private final ObjectProperty<Status> statusProperty = new SimpleObjectProperty<>(Status.Created);

  /** The group of the wave used to dispatch the right event. */
  private WaveGroup waveGroup = WaveGroup.UNDEFINED;

  /** The type of the wave used to call the right method name of the receiver object. */
  private WaveType waveType;

  /** The from class to used for create waves. */
  private Class<?> fromClass;

  /** The related component class to used for create waves. */
  private Class<?> componentClass;

  /** The priority used to process wave according to a custom order. */
  private int priority;

  /**
   * The related wave to the current wave, cold be a parent wave or child wave according context.
   */
  private Wave relatedWave;

  /** A map used to contain all data. */
  private final Map<WaveItem<?>, WaveData<?>> waveItemsMap = new HashMap<>();

  /** A sorted list that contains all data. */
  private final List<WaveData<?>> waveDataList = new ArrayList<>();

  /** The wave bean. */
  private Map<Class<? extends WaveBean>, WaveBean> waveBeanMap;

  /** The type extending WaveBean to use to embed some values. */
  // private Class<? extends WaveBean> waveBeanClass;

  /** The list of wave Listener to warn when wave status changed. */
  private final List<WaveListener> waveListeners =
      Collections.synchronizedList(new ArrayList<WaveListener>());

  /** The list of Wave Handlers used to manage the Handled status. */
  private List<? extends Object> waveHandlers;

  /** Default Constructor. */
  WaveBase() {
    super();
    // Generate a random but unique identifier
    this.wuid = UUID.randomUUID().toString();
    // Store the creation date
    this.timestamp = System.currentTimeMillis();
  }

  /** {@inheritDoc} */
  @Override
  public WaveGroup waveGroup() {
    return this.waveGroup;
  }

  /** {@inheritDoc} */
  @Override
  public Wave waveGroup(final WaveGroup waveGroup) {
    this.waveGroup = waveGroup;
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public WaveType waveType() {
    return this.waveType;
  }

  /** {@inheritDoc} */
  @Override
  public Wave waveType(final WaveType waveType) {
    this.waveType = waveType;
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Class<?> fromClass() {
    return this.fromClass;
  }

  /** {@inheritDoc} */
  @Override
  public Wave fromClass(final Class<?> fromClass) {
    this.fromClass = fromClass;
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Class<?> componentClass() {
    return this.componentClass;
  }

  /** {@inheritDoc} */
  @Override
  public Wave componentClass(final Class<?> componentClass) {
    this.componentClass = componentClass;
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public int priority() {
    return this.priority;
  }

  /** {@inheritDoc} */
  @Override
  public Wave priority(final int priority) {
    this.priority = priority;
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Wave relatedWave() {
    return this.relatedWave;
  }

  /** {@inheritDoc} */
  @Override
  public Wave relatedWave(final Wave nextWave) {
    this.relatedWave = nextWave;
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public List<WaveData<?>> waveDatas() {
    return this.waveDataList;
  }

  /** {@inheritDoc} */
  @Override
  public Wave addDatas(final WaveData<?>... waveDatas) {

    for (final WaveData<?> waveData : waveDatas) {

      // Init the order of the wave Data
      waveData.setOrder(waveDatas().size());

      // Grab the previous value if any
      final WaveData<?> previous = this.waveItemsMap.get(waveData.getKey());

      // Store into the map to allow access by WaveItem
      this.waveItemsMap.put(waveData.getKey(), waveData);

      // Remove the old value from the list
      if (previous != null) {
        this.waveDataList.remove(previous);
      }

      // Add into the list to enable sorting
      this.waveDataList.add(waveData);

      // Sort the list
      Collections.sort(this.waveDataList);
    }
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public <T> Wave add(final WaveItem<T> waveItem, final T value) {
    final WaveData<T> waveData = Builders.waveData(waveItem, value);
    addDatas(waveData);
    return this;
  }

  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public <T> WaveData<T> getData(final WaveItem<T> waveItem) {
    return (WaveData<T>) this.waveItemsMap.get(waveItem);
  }

  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public <T> T get(final WaveItem<T> waveItem) {
    return (T)
        (this.waveItemsMap.containsKey(waveItem)
            ? this.waveItemsMap.get(waveItem).getValue()
            : null);
  }

  /** {@inheritDoc} */
  @Override
  public boolean contains(final WaveItem<?> waveItem) {
    return this.waveItemsMap.containsKey(waveItem);
  }

  /** {@inheritDoc} */
  @Override
  public boolean containsNotNull(final WaveItem<?> waveItem) {
    return contains(waveItem) && getData(waveItem).getValue() != null;
  }

  /** {@inheritDoc} */
  @Override
  public String getWUID() {
    return this.wuid;
  }

  /** {@inheritDoc} */
  @Override
  public long getTimestamp() {
    return this.timestamp;
  }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public WaveBean waveBean() {
  // if (this.waveBean == null) {
  // if (this.waveBeanClass == null || WaveBean.class.equals(this.waveBeanClass)) {
  // // Build an empty wave bean to avoid null pointer exception
  // this.waveBean = new DefaultWaveBean();
  // } else {
  // try {
  // this.waveBean = this.waveBeanClass.newInstance();
  // } catch (InstantiationException | IllegalAccessException e) {
  // LOGGER.error(WAVE_BEAN_CREATION_ERROR, e, this.waveBeanClass.toString());
  // } finally {
  // if (this.waveBean == null) {
  // this.waveBean = new DefaultWaveBean();
  // }
  // }
  // }
  // }
  //
  // return this.waveBean;
  // }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public Wave waveBean(final WaveBean waveBean) {
  // if (waveBean != null) {
  // this.waveBean = waveBean;
  // this.waveBeanClass = waveBean.getClass();
  // }
  // return this;
  // }

  /** {@inheritDoc} */
  @Override
  public Wave waveBean(final WaveBean waveBean) {
    if (this.waveBeanMap == null) {
      this.waveBeanMap = new HashMap<>();
    }
    this.waveBeanMap.put(waveBean.getClass(), waveBean);
    // this.waveBeanClass = waveBean.getClass();
    return this;
  }

  /** {@inheritDoc} */
  // @Override
  @Override
  public <WB extends WaveBean> WB waveBean(final Class<WB> waveBeanClass) {
    if (this.waveBeanMap == null) {
      this.waveBeanMap = new HashMap<>();
    }
    if (!this.waveBeanMap.containsKey(waveBeanClass)) {
      try {
        final WB waveBean = waveBeanClass.newInstance();

        this.waveBeanMap.put(waveBeanClass, waveBean);

      } catch (InstantiationException | IllegalAccessException e) {
        LOGGER.error(WAVE_BEAN_CREATION_ERROR, e, waveBeanClass.toString());
      } finally {
        // if (this.waveBean == null) {
        // this.waveBean = new DefaultWaveBean();
        // }
      }
    }

    return (WB) this.waveBeanMap.get(waveBeanClass);
  }

  //
  // /**
  // * @return Returns the waveBeanClass.
  // */
  // public Class<? extends WaveBean> getWaveBeanClass() {
  // return this.waveBeanClass;
  // }

  // /**
  // * @param waveBeanClass The waveBeanClass to set.
  // */
  // public void setWaveBeanClass(final Class<? extends WaveBean> waveBeanClass) {
  // this.waveBeanClass = waveBeanClass;
  // }

  /** {@inheritDoc} */
  @Override
  public List<WaveBean> waveBeanList() {
    return new ArrayList<>(this.waveBeanMap.values());
  }

  /** {@inheritDoc} */
  @Override
  public Wave waveBeanList(final List<WaveBean> waveBeanList) {

    if (waveBeanList != null && !waveBeanList.isEmpty()) {
      if (this.waveBeanMap == null) {
        this.waveBeanMap = new HashMap<>();
      }
      waveBeanList.forEach(wb -> this.waveBeanMap.put(wb.getClass(), wb));
    }
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Wave addWaveListener(final WaveListener waveListener) {
    this.waveListeners.add(waveListener);
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Wave removeWaveListener(final WaveListener waveListener) {
    this.waveListeners.remove(waveListener);
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Status status() {
    synchronized (this) {
      return this.statusProperty.get();
    }
  }

  /** {@inheritDoc} */
  @Override
  public ObjectProperty<Status> statusProperty() {
    return this.statusProperty;
  }

  /** {@inheritDoc} */
  @Override
  public Wave status(final Status status) {
    synchronized (this) {
      if (this.statusProperty.get() == status) {
        // throw new CoreRuntimeException("The status " + status.toString() + " has been already set
        // for this wave " + toString());
      } else {
        this.statusProperty.set(status);
        fireStatusChanged();
      }
    }
    return this;
  }

  /** Fire a wave status change. */
  private void fireStatusChanged() {
    // System.out.println("fireStatusChanged " + this.status.toString());

    for (final WaveListener waveListener : this.waveListeners) {

      switch (this.statusProperty.get()) {
        case Created:
          waveListener.waveCreated(this);
          break;
        case Sent:
          waveListener.waveSent(this);
          break;
        case Processing:
          waveListener.waveProcessed(this);
          break;
        case Consumed:
          waveListener.waveConsumed(this);
          break;
        case Handled:
          waveListener.waveHandled(this);
          break;
        case Failed:
          waveListener.waveFailed(this);
          break;
        default:
          break;
      }
    }
  }

  /** {@inheritDoc} */
  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder();

    if (waveGroup() != null) {
      sb.append(waveGroup()).append(SPACE_SEP);
    }
    if (fromClass() != null) {
      sb.append("fromClass=").append(fromClass().getSimpleName()).append(SPACE_SEP);
    }
    if (componentClass() != null) {
      sb.append("relatedClass=").append(componentClass().getSimpleName()).append(SPACE_SEP);
    }
    if (waveType() != null) {
      sb.append(waveType()).append(SPACE_SEP);
    }

    if (getWUID() != null) {
      sb.append("(").append(getWUID()).append(") ");
    }

    if (waveDatas().size() > 0) {
      sb.append("\r\nData=>");
      for (final WaveData<?> wd : waveDatas()) {
        sb.append(wd.getKey()).append("=").append(wd.getValue());
      }
    }

    return sb.toString();
  }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public Wave waveBean(final WaveBean waveBean) {
  // if (waveBean != null) {
  // this.waveBean = waveBean;
  // this.waveBeanClass = waveBean.getClass();
  // }
  // return this;
  // }

  /** {@inheritDoc} */
  @Override
  public void setWaveHandlers(final List<? extends Object> waveHandlers) {
    this.waveHandlers = waveHandlers;
  }

  /** {@inheritDoc} */
  @Override
  public void removeWaveHandler(final Object waveHandler) {
    if (waveHandler != null) {
      // Remove the handler that has terminated
      this.waveHandlers.remove(waveHandler);

      // Update the status if required
      if (status() == Status.Consumed && this.waveHandlers.isEmpty()) {
        status(Status.Handled);
      }
    }
  }

  /** {@inheritDoc} */
  @Override
  public boolean hasWaveBean(final Class<? extends WaveBean> waveBeanClass) {
    if (this.waveBeanMap != null && !this.waveBeanMap.isEmpty()) {
      return this.waveBeanMap.containsKey(waveBeanClass);
    }
    return false;
  }
}
/**
 * The class <strong>JRebirthThreadPoolExecutor</strong> is used to to manage the JRebirth Thread
 * Pool (<b>JTP</b>).
 *
 * @author Sébastien Bordes
 */
public class JRebirthThreadPoolExecutor extends ThreadPoolExecutor implements ConcurrentMessages {

  /** The class logger. */
  private static final JRLogger LOGGER =
      JRLoggerFactory.getLogger(JRebirthThreadPoolExecutor.class);

  /** The pending list of JRebirthRunnable. */
  private final List<JRebirthRunnable> pending = new ArrayList<>();

  /**
   * Default Constructor.
   *
   * @param threadNumber the number of thread managed by the pool
   * @param threadFactory the factory used to add a thread into the pool
   */
  public JRebirthThreadPoolExecutor(final int threadNumber, final ThreadFactory threadFactory) {
    super(
        threadNumber,
        threadNumber,
        0L,
        TimeUnit.MILLISECONDS,
        new PriorityBlockingQueue<Runnable>(threadNumber, new JRebirthRunnableComparator()),
        threadFactory);
  }

  /**
   * Check if a slot is available for the given task priority.
   *
   * @param taskPriority the priority to check
   * @return true if this priority can be run right now
   */
  public boolean checkAvailability(final RunnablePriority taskPriority) {

    // The next task could be added if:
    // _ a slot is available
    // _ the task has a lower priority than current executed

    return getActiveCount() < getCorePoolSize() || checkPriority(taskPriority);
  }

  /**
   * Check given priority with current pending list.
   *
   * @param taskPriority the priority to check
   * @return true if the priority is greater than those pending
   */
  private boolean checkPriority(final RunnablePriority taskPriority) {
    boolean highPriority = false;
    for (final JRebirthRunnable jr : this.pending) {
      highPriority |= taskPriority.getLevel() > jr.getPriority().getLevel();
    }
    return !highPriority;
  }

  // /**
  // * Execute the JRebirthRunnable.
  // *
  // * @param task to run
  // */
  // public void execute(final JRebirthRunnable task) {
  // super.execute(task);
  // }

  /** {@inheritDoc} */
  @Override
  protected void beforeExecute(final Thread t, final Runnable r) {

    this.pending.add((JRebirthRunnable) r);

    super.beforeExecute(t, r);
  }

  /** {@inheritDoc} */
  @Override
  protected void afterExecute(final Runnable r, final Throwable t) {
    super.afterExecute(r, t);

    this.pending.remove(r);

    Throwable rootCause = null;
    if (t == null && r instanceof Future<?>) {
      try {
        final Object result = ((Future<?>) r).get();
        if (result != null) {
          LOGGER.log(FUTURE_DONE, r.hashCode(), result.toString());
        }
      } catch (final CancellationException | ExecutionException e) {
        rootCause = e.getCause();
      } catch (final InterruptedException ie) {
        Thread.currentThread().interrupt(); // ignore/reset
      }
    }
    if (t != null) {
      LOGGER.log(JTP_ERROR, t);
    }
    if (rootCause != null) {
      LOGGER.log(JTP_ERROR_EXPLANATION, rootCause);
    }
  }
}
Exemplo n.º 3
0
/**
 * The class <strong>FXMLUtils</strong>.
 *
 * @author Sébastien Bordes
 */
public final class FXMLUtils implements FXMLMessages {

  /** The class logger. */
  private static final JRLogger LOGGER = JRLoggerFactory.getLogger(FXMLUtils.class);

  /** Private constructor. */
  private FXMLUtils() {
    // Nothing to do
  }

  /**
   * Load a FXML component without resource bundle.
   *
   * <p>The fxml path could be :
   *
   * <ul>
   *   <li>Relative : fxml file will be loaded with the classloader of the given model class
   *   <li>Absolute : fxml file will be loaded with default thread class loader, packages must be
   *       separated by / character
   * </ul>
   *
   * @param model the model that will manage the fxml node
   * @param fxmlPath the fxml string path
   * @return a FXMLComponent object that wrap a fxml node with its controller
   * @param <M> the model type that will manage this fxml node
   */
  public static <M extends Model> FXMLComponentBase loadFXML(final M model, final String fxmlPath) {
    return loadFXML(model, fxmlPath, null);
  }

  /**
   * Load a FXML component.
   *
   * <p>The fxml path could be :
   *
   * <ul>
   *   <li>Relative : fxml file will be loaded with the classloader of the given model class
   *   <li>Absolute : fxml file will be loaded with default thread class loader, packages must be
   *       separated by / character
   * </ul>
   *
   * @param model the model that will manage the fxml node
   * @param fxmlPath the fxml string path
   * @param bundlePath the bundle string path
   * @return a FXMLComponent object that wrap a fxml node with its controller
   * @param <M> the model type that will manage this fxml node
   */
  @SuppressWarnings("unchecked")
  public static <M extends Model> FXMLComponentBase loadFXML(
      final M model, final String fxmlPath, final String bundlePath) {

    final FXMLLoader fxmlLoader = new FXMLLoader();

    // Use Custom controller factory to attach the root model to the controller
    fxmlLoader.setControllerFactory(new DefaultFXMLControllerBuilder(model));

    fxmlLoader.setLocation(convertFxmlUrl(model, fxmlPath));

    try {
      if (bundlePath != null) {
        fxmlLoader.setResources(ResourceBundle.getBundle(bundlePath));
      }
    } catch (final MissingResourceException e) {
      LOGGER.log(MISSING_RESOURCE_BUNDLE, e, bundlePath);
    }

    Node node = null;
    boolean error = false;
    try {
      error = fxmlLoader.getLocation() == null;
      if (error) {
        node = TextBuilder.create().text(FXML_ERROR_NODE_LABEL.getText(fxmlPath)).build();
      } else {
        node = (Node) fxmlLoader.load(fxmlLoader.getLocation().openStream());
      }

    } catch (final IOException e) {
      throw new CoreRuntimeException(FXML_NODE_DOESNT_EXIST.getText(fxmlPath), e);
    }

    final FXMLController<M, ?> fxmlController = (FXMLController<M, ?>) fxmlLoader.getController();

    // It's tolerated to have a null controller for an fxml node
    if (fxmlController != null) {
      // The fxml controller must extends AbstractFXMLController
      if (!error && !(fxmlLoader.getController() instanceof AbstractFXMLController)) {
        throw new CoreRuntimeException(
            BAD_FXML_CONTROLLER_ANCESTOR.getText(
                fxmlLoader.getController().getClass().getCanonicalName()));
      }
      // Link the View component with the fxml controller
      fxmlController.setModel(model);
    }

    return new FXMLComponentBase(node, fxmlController);
  }

  /**
   * Convert The url of fxml files to allow local and path loading.
   *
   * @param model the model class that will be used for relative loading
   * @param fxmlPath the path of the fxml file (relative or absolute)
   * @return the FXML file URL
   * @param <M> the model type that will manage this fxml node
   */
  private static <M extends Model> URL convertFxmlUrl(final M model, final String fxmlPath) {
    URL fxmlUrl = null;
    // Replace all '.' separator by path separator '/'
    if (model != null) {
      // Try to load the resource from the same path as the model class
      fxmlUrl = model.getClass().getResource(fxmlPath);
    }
    if (fxmlUrl == null) {
      // Try to load the resource from the full path org/jrebirth/core/ui/Test.fxml
      fxmlUrl = Thread.currentThread().getContextClassLoader().getResource(fxmlPath);
    }

    return fxmlUrl;
  }
}