Package org.waveprotocol.box.server.waveserver

Source Code of org.waveprotocol.box.server.waveserver.ImportServlet

/**
* Copyright 2012 A. Kaplanov
*
* 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 org.waveprotocol.box.server.waveserver;

import com.google.gxp.org.apache.xerces.impl.dv.util.Base64;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.protobuf.ByteString;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import org.waveprotocol.box.server.persistence.AttachmentStore;
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.model.wave.InvalidParticipantAddress;
import org.waveprotocol.wave.util.logging.Log;
import org.waveprotocol.wave.federation.Proto.ProtocolAppliedWaveletDelta;
import org.waveprotocol.wave.federation.Proto.ProtocolHashedVersion;
import org.waveprotocol.wave.federation.Proto.ProtocolWaveletDelta;
import org.waveprotocol.wave.federation.Proto.ProtocolWaveletOperation;
import org.waveprotocol.wave.model.id.IdURIEncoderDecoder;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.id.WaveletName;
import org.waveprotocol.wave.model.version.HashedVersionFactory;
import org.waveprotocol.wave.model.version.HashedVersionFactoryImpl;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.util.escapers.jvm.JavaUrlCodec;

/**
*
* @author (akaplanov@gmail.com) (Andrew Kaplanov)
*/
@SuppressWarnings("serial")
@Singleton
public class ImportServlet extends HttpServlet {

  private static final Log LOG = Log.get(ImportServlet.class);
  public static final String GWAVE_PUBLIC_DOMAIN = "a.gwave.com";
  public static final String GWAVE_PUBLIC_USER_NAME = "public";
  public static final String WIAB_SHARED_USER_NAME = "";
  private static final IdURIEncoderDecoder URI_CODEC = new IdURIEncoderDecoder(new JavaUrlCodec());
  private static final HashedVersionFactory HASH_FACTORY = new HashedVersionFactoryImpl(URI_CODEC);
  private final WaveletProvider waveletProvider;
  private final AttachmentStore attachmentStore;
  private final WaveMap waveMap;

  @Inject
  private ImportServlet(WaveletProvider waveletProvider, AttachmentStore attachmentStore,
      WaveMap waveMap) {
    this.waveletProvider = waveletProvider;
    this.attachmentStore = attachmentStore;
    this.waveMap = waveMap;
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    String domain = request.getHeader("domain");
    WaveId waveId = WaveId.deserialise(request.getHeader("waveId"));
    WaveletId waveletId = WaveletId.deserialise(request.getHeader("waveletId"));
    final StringWriter error = new StringWriter();
    boolean somethingProcessed = false;
    boolean somethingSkipped = false;
    try {
      JSONObject exp = new JSONObject(readToString(request.getReader()));
      JSONArray rawDeltas = exp.getJSONObject("data").getJSONArray("rawDeltas");
      if (rawDeltas.length() != 0) {
        List<ProtocolAppliedWaveletDelta> deltas = new LinkedList<ProtocolAppliedWaveletDelta>();
        for (int i = 0; i < rawDeltas.length(); i++) {
          deltas.add(ProtocolAppliedWaveletDelta.parseFrom(Base64.decode(rawDeltas.getString(i))));
        }
        WaveletName waveletName = WaveletName.of(waveId, waveletId);
        LocalWaveletContainerImpl wavelet = (LocalWaveletContainerImpl) waveMap.getLocalWavelet(waveletName);
        Set<ParticipantId> participants = new HashSet<ParticipantId>();
        if (wavelet != null) {
          participants.addAll(wavelet.accessSnapshot().getParticipants());
        }
        for (ProtocolAppliedWaveletDelta appliedDelta : deltas) {
          ProtocolWaveletDelta delta = ProtocolWaveletDelta.parseFrom(
              appliedDelta.getSignedOriginalDelta().getDelta());
          long currentVersion = 0;
          if (wavelet != null) {
            currentVersion = wavelet.getCurrentVersion().getVersion();
          }
          if (currentVersion == delta.getHashedVersion().getVersion()) {
            ProtocolWaveletDelta newDelta = convertDelta(delta, domain, wavelet, waveletName,
                participants);

            waveletProvider.submitRequest(waveletName, newDelta,
                new WaveletProvider.SubmitRequestListener() {

                  @Override
                  public void onSuccess(int operationsApplied, HashedVersion hashedVersionAfterApplication,
                      long applicationTimestamp) {
                  }

                  @Override
                  public void onFailure(String errorMessage) {
                    error.write(errorMessage);
                  }
                });
            if (error.getBuffer().length() != 0) {
              break;
            }
            if (wavelet == null) {
              wavelet = (LocalWaveletContainerImpl) waveMap.getLocalWavelet(waveletName);
            }
            somethingProcessed = true;
          } else {
            somethingSkipped = true;
          }
        }
      }
    } catch (Exception ex) {
      LOG.log(Level.SEVERE, "waveId " + waveId.toString() + ", waveletId " + waveletId.toString(), ex);
      throw new IOException(ex);
    }
    response.setStatus(HttpServletResponse.SC_OK);
    if (error.getBuffer().length() != 0) {
      response.getOutputStream().write(("error : " + error.getBuffer()).getBytes());
    } else if (somethingProcessed && !somethingSkipped) {
      response.getOutputStream().write(("imported").getBytes());
    } else if (somethingProcessed && somethingSkipped) {
      response.getOutputStream().write(("appended").getBytes());
    } else {
      response.getOutputStream().write(("skipped").getBytes());
    }
  }

  /**
   * Convert delta from GWave to Wiab
   *
   * @param delta from GWave
   * @param domain target domain
   * @param wavelet to append delta
   * @param waveletName name of wavelet
   * @param set participants of wavelet at this moment
   * @return delta to import
   * @throws InvalidParticipantAddress deserialize of participant error
   */
  protected static ProtocolWaveletDelta convertDelta(ProtocolWaveletDelta delta, String domain,
      LocalWaveletContainerImpl wavelet, WaveletName waveletName,
      Set<ParticipantId> participants) throws InvalidParticipantAddress {
    ProtocolWaveletDelta.Builder newDelta = ProtocolWaveletDelta.newBuilder(delta);
    ParticipantId creator = null;
    if (wavelet != null) {
      creator = wavelet.getCreator();
    }
    ParticipantId author = makeParticipantId(delta.getAuthor(), domain);
    if (!participants.contains(author) && creator != null) {
      // Assign the authorship of the delta from internal GWave users
      // (panda@a.gwave.com, spelly@a.gwave.com) or others to the creator of wave.
      if (!author.getAddress().endsWith("@" + GWAVE_PUBLIC_DOMAIN)) {
        LOG.warning("Unknown participant " + author.getAddress()
            + ", wave " + wavelet.getWaveletName().waveId.getId());
      }
      author = creator;
    }
    newDelta.setAuthor(author.getAddress());
    for (int i = 0; i < delta.getOperationCount(); i++) {
      ProtocolWaveletOperation op = delta.getOperation(i);
      ProtocolWaveletOperation.Builder newOp = ProtocolWaveletOperation.newBuilder(op);
      if (op.hasAddParticipant()) {
        initAddParticipantOperation(newOp, op, domain, participants);
        if (creator == null && newOp.hasAddParticipant()) {
          creator = ParticipantId.of(newOp.getAddParticipant());
        }
      } else if (op.hasRemoveParticipant()) {
        initRemoveParticipantOperation(newOp, op, domain, participants);
      }
      // TODO (Andrew Kaplanov) import attachments
      newDelta.setOperation(i, newOp);
    }
    if (wavelet == null) {
      ProtocolHashedVersion ver = ProtocolHashedVersion.newBuilder(delta.getHashedVersion()).
          setHistoryHash(ByteString.copyFrom(HASH_FACTORY.createVersionZero(waveletName).getHistoryHash())).
          build();
      newDelta.setHashedVersion(ver);
    } else {
      ProtocolHashedVersion ver = ProtocolHashedVersion.newBuilder(delta.getHashedVersion()).
          setHistoryHash(ByteString.copyFrom(wavelet.getCurrentVersion().getHistoryHash())).
          build();
      newDelta.setHashedVersion(ver);
    }
    return newDelta.build();
  }

  /**
   * Convert adding participant operation.
   * Skip operation if participant already exists.
   */
  private static void initAddParticipantOperation(ProtocolWaveletOperation.Builder newOperation,
      ProtocolWaveletOperation operation, String domain,
      Set<ParticipantId> participants) throws InvalidParticipantAddress {
    ParticipantId participant = makeParticipantId(operation.getAddParticipant(), domain);
    if (!participants.contains(participant)) {
      newOperation.setAddParticipant(participant.getAddress());
      participants.add(participant);
    } else {
      newOperation.setNoOp(true);
    }
  }

  /**
   * Convert removal participant operation.
   * Skip operation if nothing to remove.
   */
  private static void initRemoveParticipantOperation(ProtocolWaveletOperation.Builder newOperation,
      ProtocolWaveletOperation operation, String domain,
      Set<ParticipantId> participants) throws InvalidParticipantAddress {
    ParticipantId participant = makeParticipantId(operation.getRemoveParticipant(), domain);
    if (participants.contains(participant)) {
      newOperation.setRemoveParticipant(participant.getAddress());
      participants.remove(participant);
    } else {
      newOperation.setNoOp(true);
    }
  }

  /**
   * Make WIAB participant Id
   *
   * @param participant in GWave
   * @param domain of WIAB server
   */
  private static ParticipantId makeParticipantId(String participant, String domain)
      throws InvalidParticipantAddress {
    int index = participant.indexOf('@');
    if (index != -1) {
      if (participant.substring(0, index).equals(GWAVE_PUBLIC_USER_NAME)
          && participant.substring(index + 1).equals(GWAVE_PUBLIC_DOMAIN)) {
        participant = WIAB_SHARED_USER_NAME + "@" + domain;
      } else {
        participant = participant.substring(0, index + 1) + domain;
      }
    }
    return ParticipantId.of(participant);
  }

  private static String readToString(Reader reader) throws FileNotFoundException, IOException {
    StringBuilder sb = new StringBuilder();
    char buf[] = new char[1000];
    for (;;) {
      int ret = reader.read(buf, 0, buf.length);
      if (ret == -1) {
        break;
      }
      sb.append(buf, 0, ret);
    }
    return sb.toString();
  }
}
TOP

Related Classes of org.waveprotocol.box.server.waveserver.ImportServlet

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.