Package com.google.walkaround.wave.server

Source Code of com.google.walkaround.wave.server.WalkaroundServerModule

/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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.
*/

package com.google.walkaround.wave.server;

import com.google.appengine.api.backends.BackendService;
import com.google.appengine.api.backends.BackendServiceFactory;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.channel.ChannelService;
import com.google.appengine.api.channel.ChannelServiceFactory;
import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceConfig;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.ImplicitTransactionManagementPolicy;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.ReadPolicy;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.search.SearchService;
import com.google.appengine.api.search.SearchServiceFactory;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.api.utils.SystemProperty;
import com.google.common.base.Joiner;
import com.google.inject.AbstractModule;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import com.google.walkaround.slob.server.AffinityMutationProcessor.StoreBackendInstanceCount;
import com.google.walkaround.slob.server.AffinityMutationProcessor.StoreBackendName;
import com.google.walkaround.slob.server.MutationLog;
import com.google.walkaround.slob.server.PostCommitActionIntervalMillis;
import com.google.walkaround.slob.server.PostCommitTaskUrl;
import com.google.walkaround.slob.server.SlobLocalCacheExpirationMillis;
import com.google.walkaround.slob.server.SlobMessageRouter.SlobChannelExpirationSeconds;
import com.google.walkaround.util.server.RetryHelper;
import com.google.walkaround.util.server.RetryHelper.PermanentFailure;
import com.google.walkaround.util.server.RetryHelper.RetryableFailure;
import com.google.walkaround.util.server.Util;
import com.google.walkaround.util.server.appengine.CheckedDatastore;
import com.google.walkaround.util.server.appengine.CheckedDatastore.CheckedTransaction;
import com.google.walkaround.util.server.appengine.DatastoreUtil;
import com.google.walkaround.util.server.appengine.MemcacheDeletionQueue;
import com.google.walkaround.util.server.appengine.MemcacheTable;
import com.google.walkaround.util.server.appengine.OversizedPropertyMover;
import com.google.walkaround.util.server.auth.DigestUtils2.Secret;
import com.google.walkaround.util.server.flags.FlagDeclaration;
import com.google.walkaround.util.server.flags.FlagFormatException;
import com.google.walkaround.util.server.flags.JsonFlags;
import com.google.walkaround.util.server.gwt.StackTraceDeobfuscator.SymbolMapsDirectory;
import com.google.walkaround.util.server.gwt.ZipSymbolMapsDirectory;
import com.google.walkaround.util.shared.RandomBase64Generator.RandomProvider;
import com.google.walkaround.util.shared.RandomProviderAdapter;
import com.google.walkaround.wave.server.auth.OAuthInterstitialHandler.Scopes;
import com.google.walkaround.wave.server.conv.PermissionCache.PermissionCacheExpirationSeconds;
import com.google.walkaround.wave.server.googleimport.ImportTaskQueue;
import com.google.walkaround.wave.server.model.LegacyDeltaEntityConverter;
import com.google.walkaround.wave.server.model.ServerMessageSerializer;
import com.google.walkaround.wave.shared.MessageSerializer;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;
import java.util.jar.JarFile;
import java.util.logging.Logger;

/**
* @author ohler@google.com (Christian Ohler)
*/
public class WalkaroundServerModule extends AbstractModule {

  @SuppressWarnings("unused")
  private static final Logger log = Logger.getLogger(WalkaroundServerModule.class.getName());

  private static final String CONTACTS_SCOPE = "https://www.google.com/m8/feeds/";
  private static final String WAVE_SCOPE = "http://wave.googleusercontent.com/api/rpc";

  private static final String SECRET_ENTITY_KIND = "Secret";
  private static final com.google.appengine.api.datastore.Key SECRET_KEY =
      KeyFactory.createKey(SECRET_ENTITY_KIND, "secret");
  private static final String SECRET_PROPERTY = "secret";

  private <T> void bindToFlag(Class<T> type, Class<? extends Annotation> annotation,
      FlagName flagName) {
    bind(Key.get(type, annotation))
        .toProvider(getProvider(Key.get(type, new FlagName.FlagImpl(flagName))));
  }

  @Override
  protected void configure() {
    // How heavyweight is SecureRandom?  Until we know, let's use only one.
    //
    // This seems preferable over the .toInstance() below, but it doesn't work.
    //bind(SecureRandom.class).in(Singleton.class);
    final SecureRandom random = new SecureRandom();
    bind(SecureRandom.class).toInstance(random);
    bind(Random.class).to(SecureRandom.class);
    bind(RandomProvider.class).to(RandomProviderAdapter.class);

    bind(MemcacheTable.Factory.class).to(MemcacheTable.FactoryImpl.class);

    bind(SystemProperty.Environment.Value.class).toInstance(SystemProperty.environment.value());

    bind(Key.get(String.class, Scopes.class)).toInstance(
        Joiner.on(" ").join(CONTACTS_SCOPE, WAVE_SCOPE));

    bind(Key.get(Queue.class, ImportTaskQueue.class)).toInstance(QueueFactory.getQueue("import"));
    bind(Key.get(Queue.class, MemcacheDeletionQueue.class)).toInstance(
        QueueFactory.getQueue("memcache-deletion"));

    bind(String.class).annotatedWith(PostCommitTaskUrl.class).toInstance(
        WalkaroundServletModule.POST_COMMIT_TASK_PATH);

    bind(MessageSerializer.class).to(ServerMessageSerializer.class);
    bind(MutationLog.DeltaEntityConverter.class).to(LegacyDeltaEntityConverter.class);

    bind(OversizedPropertyMover.BlobWriteListener.class).toInstance(
        OversizedPropertyMover.NULL_LISTENER);

    JsonFlags.bind(binder(), Arrays.asList(FlagName.values()),
        binder().getProvider(
            Key.get(new TypeLiteral<Map<FlagDeclaration, Object>>() {}, FlagConfiguration.class)));

    bindToFlag(Integer.class, PermissionCacheExpirationSeconds.class,
        FlagName.ACCESS_CACHE_EXPIRATION_SECONDS);
    bindToFlag(String.class, StoreBackendName.class, FlagName.STORE_SERVER);
    bindToFlag(Integer.class, StoreBackendInstanceCount.class, FlagName.NUM_STORE_SERVERS);
    bindToFlag(Integer.class, SlobChannelExpirationSeconds.class,
        FlagName.OBJECT_CHANNEL_EXPIRATION_SECONDS);
    bindToFlag(Integer.class, PostCommitActionIntervalMillis.class,
        FlagName.POST_COMMIT_ACTION_INTERVAL_MILLIS);
    bindToFlag(Integer.class, SlobLocalCacheExpirationMillis.class,
        FlagName.SLOB_LOCAL_CACHE_EXPIRATION_MILLIS);
  }

  @Provides
  // The secret is read from the datastore; @Singleton to cache it for
  // efficiency.  If an admin deletes the secret entity, a new secret will be
  // generated, but existing instances will continue to use the old one.
  // Re-deploying should fix this since it restarts all instances.
  @Singleton
  Secret provideSecret(final CheckedDatastore datastore, final Random random)
      throws PermanentFailure {
    return new RetryHelper().run(
        new RetryHelper.Body<Secret>() {
          @Override public Secret run() throws RetryableFailure, PermanentFailure {
            CheckedTransaction tx = datastore.beginTransaction();
            try {
              {
                Entity e = tx.get(SECRET_KEY);
                if (e != null) {
                  log.info("Using stored secret");
                  return Secret.of(
                      DatastoreUtil.getExistingProperty(e, SECRET_PROPERTY, Blob.class).getBytes());
                }
              }
              Secret newSecret = Secret.generate(random);
              Entity e = new Entity(SECRET_KEY);
              DatastoreUtil.setNonNullUnindexedProperty(e, SECRET_PROPERTY,
                  new Blob(newSecret.getBytes()));
              tx.put(e);
              tx.commit();
              log.info("Generated new secret");
              return newSecret;
            } finally {
              tx.close();
            }
          }
        });
  }

  @Provides
  @FlagConfiguration
  @Singleton
  Map<FlagDeclaration, Object> provideFlagConfiguration(@Named("raw flag data") String rawFlagData)
      throws FlagFormatException {
    return JsonFlags.parse(Arrays.asList(FlagName.values()), rawFlagData);
  }

  @Provides
  @Named("raw flag data")
  @Singleton
  String provideRawFlagData(@Named("webinf root") String webinfRoot) {
    return Util.slurpRequired(webinfRoot + "/flags.json");
  }

  // TODO(ohler): Make this @Singleton without breaking GuiceSetupTest.
  @Provides @Named("buildinfo")
  String provideBuildinfo(@Named("webinf root") String webinfRoot) {
    return Util.slurpRequired(webinfRoot + "/buildinfo.txt");
  }

  @Provides
  DatastoreService provideDatastore(@DatastoreTimeoutMillis long datastoreTimeoutMillis) {
    return DatastoreServiceFactory.getDatastoreService(DatastoreServiceConfig.Builder
        .withDeadline(datastoreTimeoutMillis * 1000.0)
        .implicitTransactionManagementPolicy(ImplicitTransactionManagementPolicy.NONE)
        .readPolicy(new ReadPolicy(ReadPolicy.Consistency.STRONG)));
  }

  @Provides
  MemcacheService provideMemcache() {
    return MemcacheServiceFactory.getMemcacheService();
  }

  @Provides
  URLFetchService provideUrlFetchService() {
    return URLFetchServiceFactory.getURLFetchService();
  }

  @Provides
  BlobstoreService provideBlobstoreService() {
    return BlobstoreServiceFactory.getBlobstoreService();
  }

  @Provides
  BlobInfoFactory provideBlobInfoFactory() {
    return new BlobInfoFactory();
  }

  @Provides
  ImagesService provideImagesService() {
    return ImagesServiceFactory.getImagesService();
  }

  @Provides
  ChannelService provideChannelService() {
    return ChannelServiceFactory.getChannelService();
  }

  @Provides
  UserService provideUserService() {
    return UserServiceFactory.getUserService();
  }

  @Provides
  BackendService provideBackendService() {
    return BackendServiceFactory.getBackendService();
  }

  @Provides
  SearchService provideIndexManager() {
    return SearchServiceFactory.getSearchService();
  }

  @Provides
  SymbolMapsDirectory provideSymbolMapsDir(@Named("webinf root") String webinf) throws IOException {
    return new ZipSymbolMapsDirectory(
        new JarFile(new File(webinf, "gwt-extra.jar")), "symbolMaps");
  }

  @Provides @Named("channel api url")
  String provideChannelApiUrl() {
    return "/_ah/channel/jsapi";
  }

}
TOP

Related Classes of com.google.walkaround.wave.server.WalkaroundServerModule

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.