Ejemplo n.º 1
0
 /**
  * Sets the scope of the <code>FactoryDestination</code> that is used in <code>FactoryInstance
  * </code> creation. Scope cannot be changed to and from application scope once <code>
  * FactoryInstance</code> is initialized.
  *
  * @param scope
  */
 public void setScope(String scope) {
   if (factoryInstance != null) {
     if (FlexFactory.SCOPE_APPLICATION.equals(this.scope)
         && !FlexFactory.SCOPE_APPLICATION.equals(scope)) {
       if (Log.isWarn())
         Log.getLogger(getLogCategory())
             .warn(
                 "Current scope is "
                     + FlexFactory.SCOPE_APPLICATION
                     + " and it cannot be changed to "
                     + scope
                     + " once factory instance is initialized.");
       return;
     } else if (!FlexFactory.SCOPE_APPLICATION.equals(this.scope)
         && FlexFactory.SCOPE_APPLICATION.equals(scope)) {
       if (Log.isWarn())
         Log.getLogger(getLogCategory())
             .warn(
                 "Current scope is "
                     + this.scope
                     + " and it cannot be changed to "
                     + FlexFactory.SCOPE_APPLICATION
                     + " once factory instance is initialized.");
       return;
     }
     factoryInstance.setScope(scope);
   }
   this.scope = scope;
 }
Ejemplo n.º 2
0
  /**
   * @exclude This method is provided for a cluster peer broadcast, it is not intended to be invoked
   *     locally.
   */
  public void pushMessageFromPeer(AsyncMessage message, Boolean evalSelector) {
    if (!isStarted()) {
      Log.getLogger(LOG_CATEGORY)
          .debug(
              "Received message from peer server before server is started - ignoring: "
                  + message
                  + " evalSelector: "
                  + evalSelector);
      return;
    }
    if (debug)
      Log.getLogger(LOG_CATEGORY)
          .debug(
              "Received message from peer server: " + message + " evalSelector: " + evalSelector);

    // Update the FlexContext for this thread to indicate we're processing a message from
    // a server peer.
    FlexContext.setMessageFromPeer(true);
    // we are not confirming that replication is enabled again here, so if the remote
    // peer has replication enabled and therefore broadcast to this peer, then this peer
    // will complete the operation even if it locally does not have replication enabled
    pushMessageToClients(message, evalSelector);
    // And unset.
    FlexContext.setMessageFromPeer(false);
  }
Ejemplo n.º 3
0
  /**
   * This is called remotely from other cluster members when a new remote subscription is
   * identified.
   *
   * <p>We add or remove a remote subscription...
   */
  public void subscribeFromPeer(
      String destinationId,
      Boolean subscribe,
      String selector,
      String subtopic,
      Object remoteAddress) {
    Destination destination = getDestination(destinationId);

    RemoteSubscriptionManager subMgr =
        ((MessageDestination) destination).getRemoteSubscriptionManager();

    if (destination instanceof MessageDestination) {
      if (debug)
        Log.getLogger(MessageService.LOG_CATEGORY)
            .debug(
                "Received subscription from peer: "
                    + remoteAddress
                    + " subscribe? "
                    + subscribe
                    + " selector: "
                    + selector
                    + " subtopic: "
                    + subtopic);
      if (subscribe) subMgr.addSubscriber(remoteAddress, selector, subtopic, null);
      else subMgr.removeSubscriber(remoteAddress, selector, subtopic, null);
    } else if (Log.isError())
      Log.getLogger(LOG_CATEGORY)
          .error(
              "subscribeFromPeer called with destination: "
                  + destinationId
                  + " that is not a MessageDestination");
  }
Ejemplo n.º 4
0
  /**
   * Implement a serializer instance which wraps the subscription manager in a transient variable.
   * It will need to block out all sub/unsub messages before they are broadcast to the remote
   * server, iterate through the maps of subscriptions and for each "unique" subscription it writes
   * the selector and subtopic.
   *
   * <p>synchronization note: this assumes no add/remove subscriptions are occurring while this
   * method is called.
   *
   * @return a List of subscriptions selectors and subtopics
   */
  public Object getSubscriptionState() {
    ArrayList<String> subState = new ArrayList<String>();

    if (globalSubscribers.defaultSubscriptions != null
        && !globalSubscribers.defaultSubscriptions.isEmpty()) {
      subState.add(null); // selector string
      subState.add(null); // subtopic string
    }
    if (globalSubscribers.selectorSubscriptions != null) {
      for (String s : globalSubscribers.selectorSubscriptions.keySet()) {
        subState.add(s);
        subState.add(null); // subtopic
      }
    }
    addSubscriptionState(subState, subscribersPerSubtopic);
    addSubscriptionState(subState, subscribersPerSubtopicWildcard);

    if (Log.isDebug())
      Log.getLogger(MessageService.LOG_CATEGORY)
          .debug(
              "Retrieved subscription state to send to new cluster member for destination: "
                  + destination.getId()
                  + ": "
                  + StringUtils.NEWLINE
                  + subState);

    return subState;
  }
Ejemplo n.º 5
0
  /** Return an entry from the property descrpitor cache for a class. */
  private PropertyDescriptorCacheEntry getPropertyDescriptorCacheEntry(Class c) {
    PropertyDescriptorCacheEntry pce =
        (PropertyDescriptorCacheEntry) propertyDescriptorCache.get(c);

    try {
      if (pce == null) {
        BeanInfo beanInfo = Introspector.getBeanInfo(c, stopClass);
        pce = new PropertyDescriptorCacheEntry();
        pce.propertyDescriptors = beanInfo.getPropertyDescriptors();
        pce.propertiesByName = createPropertiesByNameMap(pce.propertyDescriptors, c.getFields());
        if (cachePropertiesDescriptors) {
          synchronized (propertyDescriptorCache) {
            PropertyDescriptorCacheEntry pce2 =
                (PropertyDescriptorCacheEntry) propertyDescriptorCache.get(c);
            if (pce2 == null) propertyDescriptorCache.put(c, pce);
            else pce = pce2;
          }
        }
      }
    } catch (IntrospectionException ex) {
      // Log failed property set errors
      if (Log.isError()) {
        Logger log = Log.getLogger(LOG_CATEGORY);
        log.error(
            "Failed to introspect object of type: " + c + " error: " + ExceptionUtil.toString(ex));
      }

      // Return an empty descriptor rather than crashing
      pce = new PropertyDescriptorCacheEntry();
      pce.propertyDescriptors = new PropertyDescriptor[0];
      pce.propertiesByName = new TreeMap();
    }
    return pce;
  }
Ejemplo n.º 6
0
  /**
   * A utility method to handle outgoing throttling results in a common way.
   *
   * @param message The message that is being throttled.
   * @param throttleResult The throttling result.
   * @param isClientLevel Whether the message is being throttled at the client level or not.
   */
  public void handleOutgoingThrottleResult(
      Message message, ThrottleResult throttleResult, boolean isClientLevel) {
    Result result = throttleResult.getResult();

    // Update the management metrics.
    if (result != Result.OK && isManaged()) {
      if (isClientLevel)
        ((ThrottleManagerControl) getControl()).incrementClientOutgoingMessageThrottleCount();
      else
        ((ThrottleManagerControl) getControl()).incrementDestinationOutgoingMessageThrottleCount();
    }

    // Result can only be IGNORE (or NONE which means no throttling)
    if (result == Result.IGNORE) {
      // Improve the detail message for IGNORE.
      if (isClientLevel)
        throttleResult.setDetail(
            "Message '"
                + message.getMessageId()
                + "' ignored: Too many messages sent to client '"
                + message.getClientId()
                + "' in too small of a time interval "
                + throttleResult.getDetail());
      else
        throttleResult.setDetail(
            "Message '"
                + message.getMessageId()
                + "' throttled: Too many messages routed by destination '"
                + message.getDestination()
                + "' in too small of a time interval "
                + throttleResult.getDetail());

      if (Log.isInfo()) Log.getLogger(LOG_CATEGORY).info(throttleResult.getDetail());
    }
  }
Ejemplo n.º 7
0
  /**
   * This method is invoked remotely via jgroups. It builds a snapshot of the local subscription
   * state and sends it back to the requesting server by calling its receiveSubscriptions method.
   *
   * @exclude
   */
  public void sendSubscriptions(String destinationId, Object remoteAddress) {
    MessageDestination destination = (MessageDestination) getDestination(destinationId);
    Object subscriptions;

    /*
     * Avoid trying to use the cluster stuff if this destination does not
     * exist or is not clustered on this server.
     */
    if (destination == null) {
      if (Log.isError())
        Log.getLogger(LOG_CATEGORY)
            .error(
                "Destination: "
                    + destinationId
                    + " does not exist on this server but we received a request for the subscription info from a peer server where the destination exists as clustered.  Check the cluster configuration for this destination and make sure it matches on all servers.");
      return;
    } else if (!destination.isClustered()) {
      if (Log.isError())
        Log.getLogger(LOG_CATEGORY)
            .error(
                "Destination: "
                    + destinationId
                    + " is not clustered on this server but we received a request for the subscription info from a peer server which is clustered.  Check the cluster configuration for this destination and make sure it matches on all servers.");
      return;
    }

    RemoteSubscriptionManager subMgr = destination.getRemoteSubscriptionManager();

    /*
     * The remote server has no subscriptions initially since it has not
     * started yet.  We initialize the server here so that when it sends
     * the first add subscription request, we'll receive it.  This is because
     * servers will not process remote add/remove subscribe requests until
     * they have received the subscription state from each server.
     */
    subMgr.setSubscriptionState(Collections.EMPTY_LIST, remoteAddress);

    /*
     * To ensure that we send the remote server a clean copy of the subscription
     * table we need to block out the code which adds/removes subscriptions and sends
     * them to remote servers between here...
     */
    try {
      subscribeLock.writeLock().lock();
      subscriptions = destination.getSubscriptionManager().getSubscriptionState();
      ClusterManager clm = getMessageBroker().getClusterManager();
      clm.invokePeerToPeerOperation(
          getClass().getName(),
          destinationId,
          "receiveSubscriptions",
          new Object[] {destinationId, subscriptions},
          remoteAddress);
    } finally {
      /* ... And here */
      subscribeLock.writeLock().unlock();
    }
  }
Ejemplo n.º 8
0
  /**
   * Broadcast this subscribe/unsubscribe message to the cluster so everyone is aware of this
   * server's interest in messages matching this selector and subtopic.
   *
   * @param subscribe are we subscribing?
   * @param selector the selector
   * @param subtopic the subtopic
   */
  protected void sendSubscriptionToPeer(boolean subscribe, String selector, String subtopic) {
    if (Log.isDebug())
      Log.getLogger(MessageService.LOG_CATEGORY)
          .debug(
              "Sending subscription to peers for subscribe? "
                  + subscribe
                  + " selector: "
                  + selector
                  + " subtopic: "
                  + subtopic);

    ((MessageService) destination.getService())
        .sendSubscribeFromPeer(destination.getId(), subscribe, selector, subtopic);
  }
Ejemplo n.º 9
0
 /**
  * This method is provided for a cluster peer broadcast, it is not invoked locally. It is used by
  * remote clients to send their subscription table to this server.
  *
  * @exclude
  */
 public void receiveSubscriptions(
     String destinationId, Object subscriptions, Object senderAddress) {
   Destination destination = getDestination(destinationId);
   if (destination instanceof MessageDestination)
     ((MessageDestination) destination)
         .getRemoteSubscriptionManager()
         .setSubscriptionState(subscriptions, senderAddress);
   else if (subscriptions != null && Log.isError())
     Log.getLogger(LOG_CATEGORY)
         .error(
             "receiveSubscriptions called with non-null value but destination: "
                 + destinationId
                 + " is not a MessageDestination");
 }
Ejemplo n.º 10
0
  /**
   * Gets the value specified by the BeanProperty
   *
   * @param instance Object to get the value from
   * @param bp the property to get
   * @return the value of the property if it exists
   */
  protected final Object getBeanValue(Object instance, BeanProperty bp) {
    String propertyName = bp.getName();
    if (bp.isRead()) {
      try {
        Object value = bp.get(instance);
        if (value != null && descriptor != null) {
          SerializationDescriptor subDescriptor =
              (SerializationDescriptor) descriptor.get(propertyName);
          if (subDescriptor != null) {
            PropertyProxy subProxy = PropertyProxyRegistry.getProxyAndRegister(value);
            subProxy = (PropertyProxy) subProxy.clone();
            subProxy.setDescriptor(subDescriptor);
            subProxy.setDefaultInstance(value);
            value = subProxy;
          }
        }
        return value;
      } catch (Exception e) {
        SerializationContext context = getSerializationContext();

        // Log failed property set errors
        if (Log.isWarn() && logPropertyErrors(context)) {
          Logger log = Log.getLogger(LOG_CATEGORY);
          log.warn(
              "Failed to get property {0} on type {1}.",
              new Object[] {propertyName, getAlias(instance)}, e);
        }

        if (!ignorePropertyErrors(context)) {
          // Failed to get property '{propertyName}' on type '{className}'.
          MessageException ex = new MessageException();
          ex.setMessage(
              FAILED_PROPERTY_READ_ERROR, new Object[] {propertyName, getAlias(instance)});
          ex.setRootCause(e);
          throw ex;
        }
      }
    } else {
      SerializationContext context = getSerializationContext();
      if (!ignorePropertyErrors(context)) {
        // Property '{propertyName}' not readable from class '{alias}'.
        MessageException ex = new MessageException();
        ex.setMessage(NON_READABLE_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});
        throw ex;
      }
    }
    return null;
  }
Ejemplo n.º 11
0
 /**
  * Sets the source of the <code>FactoryDestination</code> that is used in <code>FactoryInstance
  * </code> creation. Source cannot be changed once <code>FactoryInstance</code> is initialized and
  * the scope is application.
  *
  * @param source
  */
 public void setSource(String source) {
   if (factoryInstance != null) {
     if (FlexFactory.SCOPE_APPLICATION.equals(scope)) {
       if (Log.isWarn())
         Log.getLogger(getLogCategory())
             .warn(
                 "Source of the destination cannot be changed once "
                     + "factory instance is already initialized and it has "
                     + FlexFactory.SCOPE_APPLICATION
                     + " scope");
       return;
     }
     factoryInstance.setSource(source);
   }
   this.source = source;
 }
Ejemplo n.º 12
0
  @Override
  public void start() {
    String serviceType = getClass().getName();
    ClusterManager clm = getMessageBroker().getClusterManager();

    super.start();

    /*
     * For any destinations which are not using broadcast mode,
     * we need to init the remote subscriptions.  First we send out
     * the requestSubscription messages, then we wait for the sendSubscriptions
     * messages to come in.
     */
    for (String destName : destinations.keySet()) {
      MessageDestination dest = (MessageDestination) getDestination(destName);
      if (!dest.getServerSettings().isBroadcastRoutingMode() && dest.isClustered()) {
        initRemoteSubscriptions(destName);
      }
    }

    /* Now go through and wait for the response to these messages... */
    for (String destName : destinations.keySet()) {
      MessageDestination dest = (MessageDestination) getDestination(destName);
      if (!dest.getServerSettings().isBroadcastRoutingMode() && dest.isClustered()) {
        List members = clm.getClusterMemberAddresses(serviceType, destName);
        for (Object addr : members) {
          if (!clm.getLocalAddress(serviceType, destName).equals(addr)) {
            RemoteSubscriptionManager subMgr = dest.getRemoteSubscriptionManager();
            subMgr.waitForSubscriptions(addr);
          }
        }
      }
    }
    debug = Log.isDebug();
  }
Ejemplo n.º 13
0
  /**
   * Same as the previous method but it accepts a destination parameter as well to avoid potentially
   * costly destination lookup.
   *
   * @param message The <code>Message</code> to push to peer server nodes in the cluster.
   * @param destination The destination to push the message to.
   * @param evalSelector <code>true</code> to evaluate each remote subscriber's selector before
   *     pushing the message to them; <code>false</code> to skip selector evaluation.
   */
  public void sendPushMessageFromPeer(
      Message message, MessageDestination destination, boolean evalSelector) {
    if (!destination.isClustered()) return;

    ClusterManager clm = getMessageBroker().getClusterManager();
    if (destination.getServerSettings().isBroadcastRoutingMode()) {
      if (debug)
        Log.getLogger(LOG_CATEGORY)
            .debug(
                "Broadcasting message to peer servers: "
                    + message
                    + " evalSelector: "
                    + evalSelector);
      // tell the message service on other nodes to push the message
      clm.invokeServiceOperation(
          getClass().getName(),
          message.getDestination(),
          "pushMessageFromPeer",
          new Object[] {message, evalSelector});
    } else {
      RemoteSubscriptionManager mgr = destination.getRemoteSubscriptionManager();
      Set serverAddresses = mgr.getSubscriberIds(message, evalSelector);

      if (debug)
        Log.getLogger(LOG_CATEGORY)
            .debug(
                "Sending message to peer servers: "
                    + serverAddresses
                    + StringUtils.NEWLINE
                    + " message: "
                    + message
                    + StringUtils.NEWLINE
                    + " evalSelector: "
                    + evalSelector);

      for (Object remoteAddress : serverAddresses) {
        clm.invokePeerToPeerOperation(
            getClass().getName(),
            message.getDestination(),
            "pushMessageFromPeerToPeer",
            new Object[] {message, evalSelector},
            remoteAddress);
      }
    }
  }
Ejemplo n.º 14
0
  /**
   * Removes the subscriber, unsubscribing it from all current subscriptions. This is used by the
   * admin UI.
   *
   * @param client the client
   */
  public void removeSubscriber(MessageClient client) {
    // Sends unsub messages for each subscription for this MessageClient which
    // should mean we remove the client at the end.
    client.invalidate();

    if (getSubscriber(client.getClientId()) != null)
      Log.getLogger(MessageService.LOG_CATEGORY)
          .error("Failed to remove client: " + client.getClientId());
  }
Ejemplo n.º 15
0
  /*
  * Use this method to return to the Error log level in qa-manual app.
  *
  	<target class="flex.messaging.log.ConsoleTarget" level="Error">
      <properties>
          <prefix>[Flex] </prefix>
          <includeDate>false</includeDate>
          <includeTime>true</includeTime>
          <includeLevel>true</includeLevel>
          <includeCategory>true</includeCategory>
      </properties>
      <filters>
          <pattern>Service.*</pattern>
          <pattern>Message.*</pattern>
          <pattern>DataService.*</pattern>
          <!--<pattern>Endpoint.*</pattern>-->
      </filters>
  </target>
     */
  private short createErrorLogTarget() {
    // Remove any other targets
    Log.reset();

    // Up the logging level to debug, and create a logging target dynamically
    ConsoleTarget myTarget = new ConsoleTarget();
    myTarget.setLevel(LogEvent.ERROR);
    myTarget.setPrefix("[Flex] ");
    myTarget.setIncludeDate(false);
    myTarget.setIncludeTime(true);
    myTarget.setIncludeLevel(true);
    myTarget.setIncludeCategory(true);
    myTarget.addFilter("Service.*");
    myTarget.addFilter("Message.*");
    myTarget.addFilter("DataService.*");
    Log.addTarget(myTarget);

    return ((ConsoleTarget) Log.getTargets().get(0)).getLevel();
  }
Ejemplo n.º 16
0
  /**
   * A utility method to handle incoming throttling results in a common way.
   *
   * @param message The message that is being throttled.
   * @param throttleResult The throttling result.
   * @param isClientLevel Whether the message is being throttled at the client level or not.
   */
  protected void handleIncomingThrottleResult(
      Message message, ThrottleResult throttleResult, boolean isClientLevel) {
    Result result = throttleResult.getResult();

    // Update the management metrics.
    if (result != Result.OK && isManaged()) {
      if (isClientLevel)
        ((ThrottleManagerControl) getControl()).incrementClientIncomingMessageThrottleCount();
      else
        ((ThrottleManagerControl) getControl()).incrementDestinationIncomingMessageThrottleCount();
    }

    // Result can be IGNORE or ERROR (or NONE which means no throttling).
    if (result == Result.IGNORE || result == Result.ERROR) {
      if (isClientLevel)
        throttleResult.setDetail(
            "Message '"
                + message.getMessageId()
                + "' throttled: Too many messages sent by the client '"
                + message.getClientId()
                + "' in too small of a time interval "
                + throttleResult.getDetail());
      else
        throttleResult.setDetail(
            "Message '"
                + message.getMessageId()
                + "' throttled: Too many messages sent to destination '"
                + message.getDestination()
                + "' in too small of a time interval "
                + throttleResult.getDetail());

      String detail = throttleResult.getDetail();
      if (result == Result.ERROR) {
        if (Log.isError()) Log.getLogger(LOG_CATEGORY).error(detail);
        // And, throw an exception, so the client gets the error.
        MessageException me = new MessageException(detail);
        throw me;
      }
      // Otherwise, just log it.
      if (Log.isInfo()) Log.getLogger(LOG_CATEGORY).info(detail);
    }
  }
Ejemplo n.º 17
0
  void addTopicSubscribers(
      TopicSubscription ts, Message message, Set<Object> ids, boolean evalSelector) {
    if (ts == null) return;

    Map<Object, MessageClient> subs = ts.defaultSubscriptions;
    if (subs != null) ids.addAll(subs.keySet());

    if (ts.selectorSubscriptions == null) return;

    for (Map.Entry<String, Map<Object, MessageClient>> entry :
        ts.selectorSubscriptions.entrySet()) {
      String selector = entry.getKey();
      subs = entry.getValue();

      if (!evalSelector) {
        ids.addAll(subs.keySet());
      } else {
        JMSSelector jmsSel = new JMSSelector(selector);
        try {
          if (jmsSel.match(message)) {
            ids.addAll(subs.keySet());
          }
        } catch (JMSSelectorException jmse) {
          if (Log.isWarn()) {
            Log.getLogger(JMSSelector.LOG_CATEGORY)
                .warn(
                    "Error processing message selector: "
                        + jmsSel
                        + StringUtils.NEWLINE
                        + "  incomingMessage: "
                        + message
                        + StringUtils.NEWLINE
                        + "  selector: "
                        + selector);
          }
        }
      }
    }
  }
Ejemplo n.º 18
0
  /*
  * The purpose of this method is to replace the default "Error" logging target
  * with Debug log level and specific filters.
  * Verification of the log must be manually done against the console output.
  *
  	<target class="flex.messaging.log.ConsoleTarget" level="Debug">
      <properties>
          <prefix>[LCDS] </prefix>
          <includeDate>false</includeDate>
          <includeTime>true</includeTime>
          <includeLevel>true</includeLevel>
          <includeCategory>true</includeCategory>
      </properties>
      <filters>
          <pattern>Service.Data.*</pattern>
          <pattern>Message.*</pattern>
      </filters>
  </target>
     */
  private short createDebugLogTarget() {
    // Remove any other targets
    Log.reset();

    // Up the logging level to debug, and create a logging target dynamically
    ConsoleTarget myTarget = new ConsoleTarget();
    myTarget.setLevel(LogEvent.DEBUG);
    myTarget.setPrefix("[LCDS] ");
    // myTarget.setIncludeDate(true);
    myTarget.setIncludeTime(true);
    myTarget.setIncludeLevel(true);
    myTarget.setIncludeCategory(true);
    // myTarget.addFilter("Startup.*");
    myTarget.addFilter("Service.Data.*");
    myTarget.addFilter("Message.*");
    myTarget.addFilter("Endpoint.*");

    // Add the new Debug target
    Log.addTarget(myTarget);

    return ((ConsoleTarget) Log.getTargets().get(0)).getLevel();
  }
Ejemplo n.º 19
0
  public String createLogTarget(String target) {
    short currentLevel = ((ConsoleTarget) Log.getTargets().get(0)).getLevel();
    String retVal =
        "Log level did not change. Default target level: " + LogEvent.getLevelString(currentLevel);

    if (target.equals("Debug")) {
      currentLevel = createDebugLogTarget();
      retVal = LogEvent.getLevelString(currentLevel);
    } else if (target.equals("Error")) {
      currentLevel = createErrorLogTarget();
      retVal = LogEvent.getLevelString(currentLevel);
    }

    return retVal;
  }
Ejemplo n.º 20
0
  /**
   * Pushes a message to all clients that are subscribed to the destination targeted by this
   * message.
   *
   * @param message The <code>Message</code> to push to the destination's subscribers.
   * @param evalSelector <code>true</code> to evaluate each subscriber's selector before pushing the
   *     message to them; <code>false</code> to skip selector evaluation.
   */
  public void pushMessageToClients(Message message, boolean evalSelector) {
    MessageDestination destination = (MessageDestination) getDestination(message);
    SubscriptionManager subscriptionManager = destination.getSubscriptionManager();
    Set subscriberIds = subscriptionManager.getSubscriberIds(message, evalSelector);

    if (debug)
      Log.getLogger(LOG_CATEGORY)
          .debug(
              "Sending message: "
                  + message
                  + StringUtils.NEWLINE
                  + "    to subscribed clientIds: "
                  + subscriberIds);

    if ((subscriberIds != null) && !subscriberIds.isEmpty()) {
      /* We have already filtered based on the selector and so pass false below */
      pushMessageToClients(destination, subscriberIds, message, false);
    }
  }
Ejemplo n.º 21
0
  /**
   * @exclude This method is used by messaging adapters to send a message to a specific set of
   *     clients that are directly connected to this server. It does not propagate the message to
   *     other servers in the cluster.
   */
  public void pushMessageToClients(
      MessageDestination destination, Set subscriberIds, Message message, boolean evalSelector) {
    if (subscriberIds != null) {
      try {
        // Place notifier in thread-local scope.
        MessageRoutedNotifier routingNotifier = new MessageRoutedNotifier(message);
        FlexContext.setMessageRoutedNotifier(routingNotifier);

        SubscriptionManager subscriptionManager = destination.getSubscriptionManager();

        for (Object clientId : subscriberIds) {
          MessageClient client = subscriptionManager.getSubscriber(clientId);

          // Skip if the client is null or invalidated.
          if (client == null || !client.isValid()) {
            if (debug)
              Log.getLogger(MessageService.LOG_CATEGORY)
                  .debug(
                      "Warning: could not find MessageClient for clientId in pushMessageToClients: "
                          + clientId
                          + " for destination: "
                          + destination.getId());
            continue;
          }

          pushMessageToClient(client, destination, message, evalSelector);
        }

        // Done with the push, notify any listeners.
        routingNotifier.notifyMessageRouted();
      } finally {
        // Unset the notifier for this message.
        FlexContext.setMessageRoutedNotifier(null);
      }
    }
  }
Ejemplo n.º 22
0
  /** @exclude */
  public Object serviceMessage(Message message, boolean throttle, MessageDestination dest) {
    if (managed) incrementMessageCount(false, message);

    if (throttle) {
      // Throttle the inbound message; also attempts to prevent duplicate messages sent by a client.
      dest = (MessageDestination) getDestination(message);
      ThrottleManager throttleManager = dest.getThrottleManager();
      if (throttleManager != null && throttleManager.throttleIncomingMessage(message))
        return null; // Message throttled.
    }

    // Block any sent messages that have a subtopic header containing
    // wildcards - wildcards are only supported in subscribe/unsubscribe
    // commands (see serviceCommand() and manageSubscriptions()).
    Object subtopicObj = message.getHeader(AsyncMessage.SUBTOPIC_HEADER_NAME);
    List<Subtopic> subtopics = null;
    if (subtopicObj != null) {
      if (subtopicObj instanceof Object[]) subtopicObj = Arrays.asList((Object[]) subtopicObj);

      if (subtopicObj instanceof String) {
        String subtopicString = (String) subtopicObj;
        if (subtopicString != null && subtopicString.length() > 0) {
          if (dest == null) dest = (MessageDestination) getDestination(message);
          Subtopic subtopic =
              testProducerSubtopic(dest.getServerSettings().getSubtopicSeparator(), subtopicString);
          if (subtopics == null) subtopics = new ArrayList<Subtopic>();
          subtopics.add(subtopic);
        }
      } else if (subtopicObj instanceof List) {
        @SuppressWarnings("unchecked")
        List<String> subtopicList = (List<String>) subtopicObj;
        String subtopicSeperator = null;
        for (String subtopicString : subtopicList) {
          if (subtopicString != null && subtopicString.length() > 0) {
            if (dest == null) dest = (MessageDestination) getDestination(message);
            subtopicSeperator = dest.getServerSettings().getSubtopicSeparator();
            Subtopic subtopic = testProducerSubtopic(subtopicSeperator, subtopicString);
            if (subtopics == null) subtopics = new ArrayList<Subtopic>();
            subtopics.add(subtopic);
          }
        }
      }
    }

    // Override TTL if there was one specifically configured for this destination
    if (dest == null) dest = (MessageDestination) getDestination(message);
    ServerSettings destServerSettings = dest.getServerSettings();
    if (destServerSettings.getMessageTTL() >= 0)
      message.setTimeToLive(destServerSettings.getMessageTTL());

    long start = 0;
    if (debug) start = System.currentTimeMillis();

    // Give MessagingAdapter a chance to block the send.
    ServiceAdapter adapter = dest.getAdapter();
    if (adapter instanceof MessagingAdapter) {
      MessagingSecurityConstraintManager manager =
          ((MessagingAdapter) adapter).getSecurityConstraintManager();
      if (manager != null) manager.assertSendAuthorization();
    }

    MessagePerformanceUtils.markServerPreAdapterTime(message);
    Object result = adapter.invoke(message);
    MessagePerformanceUtils.markServerPostAdapterTime(message);

    if (debug) {
      long end = System.currentTimeMillis();
      Log.getLogger(TIMING_LOG_CATEGORY)
          .debug("After invoke service: " + getId() + "; execution time = " + (end - start) + "ms");
    }

    return result;
  }
Ejemplo n.º 23
0
  /**
   * Add a subscriber.
   *
   * @param clientId the client id
   * @param selector the selector
   * @param subtopicString the subtopic
   * @param endpointId the endpoint
   * @param maxFrequency maximum frequency
   */
  public void addSubscriber(
      Object clientId,
      String selector,
      String subtopicString,
      String endpointId,
      int maxFrequency) {
    Subtopic subtopic = getSubtopic(subtopicString);
    MessageClient client = null;
    TopicSubscription topicSub;
    Map<Object, MessageClient> subs;
    Map<Subtopic, TopicSubscription> map;

    try {
      // Handle resubscribes from the same client and duplicate subscribes from different clients
      boolean subscriptionAlreadyExists = (getSubscriber(clientId) != null);
      client = getMessageClient(clientId, endpointId);

      FlexClient flexClient = FlexContext.getFlexClient();
      if (subscriptionAlreadyExists) {
        // Block duplicate subscriptions from multiple FlexClients if they
        // attempt to use the same clientId.  (when this is called from a remote
        // subscription, there won't be a flex client so skip this test).
        if (flexClient != null && !flexClient.getId().equals(client.getFlexClient().getId())) {
          ServiceException se = new ServiceException();
          se.setMessage(10559, new Object[] {clientId});
          throw se;
        }

        // It's a resubscribe. Reset the endpoint push state for the subscription to make sure its
        // current
        // because a resubscribe could be arriving over a new endpoint or a new session.
        client.resetEndpoint(endpointId);
      }

      ServiceAdapter adapter = destination.getAdapter();
      client.updateLastUse();

      if (subtopic == null) {
        topicSub = globalSubscribers;
      } else {
        if (!destination.getServerSettings().getAllowSubtopics()) {
          // Throw an error - the destination doesn't allow subtopics.
          ServiceException se = new ServiceException();
          se.setMessage(
              SUBTOPICS_NOT_SUPPORTED, new Object[] {subtopicString, destination.getId()});
          throw se;
        }

        if (subtopic.containsSubtopicWildcard()
            && destination.getServerSettings().isDisallowWildcardSubtopics()) {
          // Attempt to subscribe to the subtopic, ''{0}'', on destination, ''{1}'', that does not
          // allow wilcard subtopics failed.
          ServiceException se = new ServiceException();
          se.setMessage(
              WILDCARD_SUBTOPICS_NOT_ALLOWED, new Object[] {subtopicString, destination.getId()});
          throw se;
        }

        // Give a MessagingAdapter a chance to block the subscribe.
        if ((adapter instanceof MessagingSecurity) && (subtopic != null)) {
          if (!((MessagingSecurity) adapter).allowSubscribe(subtopic)) {
            ServiceException se = new ServiceException();
            se.setMessage(10557, new Object[] {subtopicString});
            throw se;
          }
        }

        /*
         * If there is a wildcard, we always need to match that subscription
         * against the producer.  If it has no wildcard, we can do a quick
         * lookup to find the subscribers.
         */
        if (subtopic.containsSubtopicWildcard()) map = subscribersPerSubtopicWildcard;
        else map = subscribersPerSubtopic;

        synchronized (this) {
          topicSub = map.get(subtopic);
          if (topicSub == null) {
            topicSub = new TopicSubscription();
            map.put(subtopic, topicSub);
          }
        }
      }

      /* Subscribing with no selector */
      if (selector == null) {
        subs = topicSub.defaultSubscriptions;
        if (subs == null) {
          synchronized (this) {
            if ((subs = topicSub.defaultSubscriptions) == null)
              topicSub.defaultSubscriptions = subs = new ConcurrentHashMap<Object, MessageClient>();
          }
        }
      }
      /* Subscribing with a selector - store all subscriptions under the selector key */
      else {
        synchronized (this) {
          if (topicSub.selectorSubscriptions == null)
            topicSub.selectorSubscriptions =
                new ConcurrentHashMap<String, Map<Object, MessageClient>>();
        }

        subs = topicSub.selectorSubscriptions.get(selector);
        if (subs == null) {
          synchronized (this) {
            if ((subs = topicSub.selectorSubscriptions.get(selector)) == null)
              topicSub.selectorSubscriptions.put(
                  selector, subs = new ConcurrentHashMap<Object, MessageClient>());
          }
        }
      }

      if (subs.containsKey(clientId)) {
        /* I'd rather this be an error but in 2.0 we allowed this without error */
        if (Log.isWarn())
          Log.getLogger(JMSSelector.LOG_CATEGORY)
              .warn(
                  "Client: "
                      + clientId
                      + " already subscribed to: "
                      + destination.getId()
                      + " selector: "
                      + selector
                      + " subtopic: "
                      + subtopicString);
      } else {
        client.addSubscription(selector, subtopicString, maxFrequency);
        synchronized (this) {
          /*
           * Make sure other members of the cluster know that we are subscribed to
           * this info if we are in server-to-server mode
           *
           * This has to be done in the synchronized section so that we properly
           * order subscribe and unsubscribe messages for our peers so their
           * subscription state matches the one in the local server.
           */
          if (subs.isEmpty()
              && destination.isClustered()
              && destination.getServerSettings().getRoutingMode() == RoutingMode.SERVER_TO_SERVER)
            sendSubscriptionToPeer(true, selector, subtopicString);
          subs.put(clientId, client);
        }
        monitorTimeout(
            client); // local operation, timeouts on remote host are not started until failover

        // Finally, if a new MessageClient was created, notify its created
        // listeners now that MessageClient's subscription state is setup.
        if (!subscriptionAlreadyExists) client.notifyCreatedListeners();
      }
    } finally {
      releaseMessageClient(client);
    }
  }
Ejemplo n.º 24
0
  void pushMessageToClient(
      MessageClient client, MessageDestination destination, Message message, boolean evalSelector) {
    // Normally we'll process the message selector criteria as part of fetching the
    // clients which should receive this message. However, because the API exposed the evalSelecor
    // flag
    // in pushMessageToClients(Set, Message, boolean), we need to run the client.testMessage()
    // method
    // here to make sure subtopic and selector expressions are evaluated correctly in this case.
    // The general code path passes evalSelector as false, so the testMessage() method is not
    // generally
    // invoked as part of a message push operation.
    if (evalSelector && !client.testMessage(message, destination)) {
      return;
    }

    // Push the message to the client. Note that client level outbound throttling
    // might still happen at the FlexClientOutboundQueueProcessor level.
    try {
      // Only update client last use if the message is not a pushed server command.
      if (!(message instanceof CommandMessage)) client.updateLastUse();

      // Remove any data in the base message that should not be included in the multicast copies.
      Map messageHeaders = message.getHeaders();
      messageHeaders.remove(Message.FLEX_CLIENT_ID_HEADER);
      messageHeaders.remove(Message.ENDPOINT_HEADER);

      // Add the default message priority headers, if it's not already set.
      int priority = destination.getServerSettings().getPriority();
      if (priority != -1) {
        Object header = message.getHeader(Message.PRIORITY_HEADER);
        if (header == null) message.setHeader(Message.PRIORITY_HEADER, priority);
      }

      // FIXME: [Pete] Investigate whether this is a performance issue.
      // We also need to ensure message ids do not expose FlexClient ids
      // message.setMessageId(UUIDUtils.createUUID());

      // We need a unique instance of the message for each client; both to prevent
      // outbound queue processing for various clients from interfering with each other
      // as well as needing to target the copy of the message to a specific MessageAgent
      // instance on the client.
      Message messageForClient = (Message) message.clone();

      // the MPIUTil call will be a no-op if MPI is not enabled.  Otherwise it will add
      // a server pre-push processing timestamp to the MPI object
      MessagePerformanceUtils.markServerPrePushTime(message);
      MessagePerformanceUtils.markServerPostAdapterTime(message);
      MessagePerformanceUtils.markServerPostAdapterExternalTime(message);

      // Target the message to a specific MessageAgent on the client.
      messageForClient.setClientId(client.getClientId());

      if (debug)
        Log.getLogger(MessageService.LOG_CATEGORY)
            .debug(
                "Routing message to FlexClient id:"
                    + client.getFlexClient().getId()
                    + "', MessageClient id: "
                    + client.getClientId());

      getMessageBroker().routeMessageToMessageClient(messageForClient, client);
    } catch (MessageException ignore) {
      // Client is subscribed but has disconnected or the network failed.
      // There's nothing we can do to correct this so just continue server processing.
    }
  }
Ejemplo n.º 25
0
  /** {@inheritDoc} */
  public void setValue(Object instance, String propertyName, Object value) {
    BeanProperty bp = getBeanProperty(instance, propertyName);

    if (bp != null) {
      if (bp.isWrite()) {
        try {
          Class desiredPropClass = bp.getType();
          TypeMarshaller marshaller = TypeMarshallingContext.getTypeMarshaller();
          value = marshaller.convert(value, desiredPropClass);
          ClassUtil.validateAssignment(instance, propertyName, value);
          bp.set(instance, value);
        } catch (Exception e) {
          SerializationContext context = getSerializationContext();

          // Log ignore failed property set errors
          if (Log.isWarn() && logPropertyErrors(context)) {
            Logger log = Log.getLogger(LOG_CATEGORY);
            log.warn(
                "Failed to set property {0} on type {1}.",
                new Object[] {propertyName, getAlias(instance)}, e);
          }

          if (!ignorePropertyErrors(context)) {
            // Failed to get property '{propertyName}' on type '{className}'.
            MessageException ex = new MessageException();
            ex.setMessage(
                FAILED_PROPERTY_WRITE_ERROR, new Object[] {propertyName, getAlias(instance)});
            ex.setRootCause(e);
            throw ex;
          }
        }
      } else {
        SerializationContext context = getSerializationContext();

        if (Log.isWarn() && logPropertyErrors(context)) {
          Logger log = Log.getLogger(LOG_CATEGORY);
          log.warn(
              "Property {0} not writable on class {1}",
              new Object[] {propertyName, getAlias(instance)});
        }

        if (!ignorePropertyErrors(context)) {
          // Property '{propertyName}' not writable on class '{alias}'.
          MessageException ex = new MessageException();
          ex.setMessage(
              NON_WRITABLE_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});
          throw ex;
        }
      }
    } else {
      SerializationContext context = getSerializationContext();

      if (Log.isWarn() && logPropertyErrors(context)) {
        Logger log = Log.getLogger(LOG_CATEGORY);
        log.warn(
            "Ignoring set property {0} for type {1} as a setter could not be found.",
            new Object[] {propertyName, getAlias(instance)});
      }

      if (!ignorePropertyErrors(context)) {
        // Property '{propertyName}' not found on class '{alias}'.
        MessageException ex = new MessageException();
        ex.setMessage(UNKNOWN_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});
        throw ex;
      }
    }
  }