Package org.waveprotocol.box.server.robots.register

Source Code of org.waveprotocol.box.server.robots.register.RobotRegistrarImpl

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

package org.waveprotocol.box.server.robots.register;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;

import org.waveprotocol.box.server.account.AccountData;
import org.waveprotocol.box.server.account.RobotAccountData;
import org.waveprotocol.box.server.account.RobotAccountDataImpl;
import org.waveprotocol.box.server.persistence.AccountStore;
import org.waveprotocol.box.server.persistence.PersistenceException;
import org.waveprotocol.box.server.robots.util.RobotsUtil.RobotRegistrationException;
import org.waveprotocol.wave.model.id.TokenGenerator;
import org.waveprotocol.wave.model.wave.ParticipantId;

import java.net.URI;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Logger;

/**
* Implements {@link RobotRegistrar}.
*
* @author yurize@apache.org (Yuri Zelikov)
*/
public class RobotRegistrarImpl implements RobotRegistrar {

  private static final Listener REGISTRATION_EVENTS_LOGGER = new Listener() {

    final Logger log = Logger.getLogger(RobotRegistrarImpl.class.getName());

    @Override
    public void onRegistrationSuccess(RobotAccountData account) {
      log.info("Registered robot: " + account.getId().getAddress() + " at " + account.getUrl());
    }

    @Override
    public void onUnregistrationSuccess(RobotAccountData account) {
      log.info("Unregistered robot: " + account.getId().getAddress() + " at " + account.getUrl());
    }
  };

  /** The length of the verification token (token secret). */
  private static final int TOKEN_LENGTH = 48;

  /** The account store. */
  private final AccountStore accountStore;

  /** The verification token generator. */
  private final TokenGenerator tokenGenerator;

  /** The list of listeners on robot un/registration events. */
  private final CopyOnWriteArraySet<Listener> listeners = new CopyOnWriteArraySet<Listener>();

  /**
   * Computes and validates the robot URL.
   *
   * @param location the robot location.
   * @return the validated robot URL in the form:
   *         [http|https]://[domain]:[port]/[path], for example:
   *         http://example.com:80/myrobot
   * @throws RobotRegistrationException if the specified URI is invalid.
   */
  private static String computeValidateRobotUrl(String location)
      throws RobotRegistrationException {
    URI uri;
    try {
      uri = URI.create(location);
    } catch (IllegalArgumentException e) {
      String errorMessage = "Invalid Location specified, please specify a location in URI format.";
      throw new RobotRegistrationException(errorMessage + " " + e.getLocalizedMessage(), e);
    }
    String scheme = uri.getScheme();
    if (scheme == null || (!scheme.equals("http") && !scheme.equals("https"))) {
      scheme = "http";
    }
    String robotLocation;
    if (uri.getPort() != -1) {
      robotLocation = scheme + "://" + uri.getHost() + ":" + uri.getPort() + uri.getPath();
    } else {
      robotLocation = scheme + "://" + uri.getHost() + uri.getPath();
    }

    if (robotLocation.endsWith("/")) {
      robotLocation = robotLocation.substring(0, robotLocation.length() - 1);
    }
    return robotLocation;
  }

  @Inject
  public RobotRegistrarImpl(AccountStore accountStore, TokenGenerator tokenGenerator) {
    this.accountStore = accountStore;
    this.tokenGenerator = tokenGenerator;
    addRegistrationListener(REGISTRATION_EVENTS_LOGGER);
  }

  @Override
  public RobotAccountData registerNew(ParticipantId robotId, String location)
      throws RobotRegistrationException, PersistenceException {
    Preconditions.checkNotNull(robotId);
    Preconditions.checkNotNull(location);
    Preconditions.checkArgument(!location.isEmpty());

    if (accountStore.getAccount(robotId) != null) {
      throw new RobotRegistrationException(robotId.getAddress()
          + " is already in use, please choose another one.");
    }
    return registerRobot(robotId, location);
  }

  @Override
  public RobotAccountData unregister(ParticipantId robotId) throws RobotRegistrationException,
      PersistenceException {
    Preconditions.checkNotNull(robotId);
    AccountData accountData = accountStore.getAccount(robotId);
    if (accountData == null) {
      return null;
    }
    throwExceptionIfNotRobot(accountData);
    RobotAccountData robotAccount = accountData.asRobot();
    removeRobotAccount(robotAccount);
    return robotAccount;
  }

  @Override
  public RobotAccountData registerOrUpdate(ParticipantId robotId, String location)
      throws RobotRegistrationException, PersistenceException {
    Preconditions.checkNotNull(robotId);
    Preconditions.checkNotNull(location);
    Preconditions.checkArgument(!location.isEmpty());

    AccountData account = accountStore.getAccount(robotId);
    if (account != null) {
      throwExceptionIfNotRobot(account);
      RobotAccountData robotAccount = account.asRobot();
      if (robotAccount.getUrl().equals(location)) {
        return robotAccount;
      } else {
        removeRobotAccount(robotAccount);
      }
    }
    return registerRobot(robotId, location);
  }

  /**
   *  Adds the robot to the account store and notifies the listeners.
   */
  private RobotAccountData registerRobot(ParticipantId robotId, String location)
      throws RobotRegistrationException, PersistenceException {
    String robotLocation = computeValidateRobotUrl(location);

    RobotAccountData robotAccount =
        new RobotAccountDataImpl(robotId, robotLocation,
            tokenGenerator.generateToken(TOKEN_LENGTH), null, true);
    accountStore.putAccount(robotAccount);
    for (Listener listener : listeners) {
      listener.onRegistrationSuccess(robotAccount);
    }
    return robotAccount;
  }

  /**
   * Removes the robot account and notifies the listeners.
   * @param existingAccount the account to remove
   * @throws PersistenceException if the persistence layer reports an error.
   */
  private void removeRobotAccount(RobotAccountData existingAccount)
      throws PersistenceException {
    accountStore.removeAccount(existingAccount.getId());
    for (Listener listener : listeners) {
      listener.onUnregistrationSuccess(existingAccount);
    }
  }

  /**
   * Ensures that the account belongs to a robot.
   *
   * @param existingAccount the account to check.
   * @throws RobotRegistrationException if the account is not robot.
   */
  private void throwExceptionIfNotRobot(AccountData existingAccount)
      throws RobotRegistrationException {
    if (!existingAccount.isRobot()) {
      throw new RobotRegistrationException(existingAccount.getId().getAddress()
          + " is not a robot account!");
    }
  }

  // Handle listeners.
  @Override
  public void addRegistrationListener(Listener listener) {
    Preconditions.checkNotNull(listener);
    listeners.add(listener);
  }

  @Override
  public void removeRegistrationListener(Listener listener) {
    Preconditions.checkNotNull(listener);
    listeners.remove(listener);
  }
}
TOP

Related Classes of org.waveprotocol.box.server.robots.register.RobotRegistrarImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.