http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/ClientRpcController.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/ClientRpcController.java b/src/org/waveprotocol/box/server/rpc/ClientRpcController.java deleted file mode 100644 index 24afd73..0000000 --- a/src/org/waveprotocol/box/server/rpc/ClientRpcController.java +++ /dev/null @@ -1,200 +0,0 @@ -/** - * 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.rpc; - -import com.google.protobuf.Message; -import com.google.protobuf.RpcCallback; -import com.google.protobuf.RpcController; - -/** - * Implements the client end-point of a wave server RPC connection. This class - * implements {{@link #reset} and is reusable across multiple RPC calls backed - * onto the same ClientRpcChannel. - * - * TODO: This class is not currently thread-safe and has some - * concurrency issues. - * - * - */ -class ClientRpcController implements RpcController { - - enum Status { - PENDING, ACTIVE, COMPLETE - } - - /** - * Internal status class to manage the state of a specific outgoing RPC. - */ - static class RpcState { - private final ClientRpcChannel creator; - private final boolean isStreamingRpc; - private final RpcCallback<Message> callback; - private final Runnable cancelRpc; - private boolean complete = false; - private boolean failed = false; - private String errorText = null; - - RpcState(ClientRpcChannel creator, boolean isStreamingRpc, RpcCallback<Message> callback, - Runnable cancelRpc) { - this.creator = creator; - this.isStreamingRpc = isStreamingRpc; - this.callback = callback; - this.cancelRpc = cancelRpc; - } - } - - // The ClientRpcChannel instance that owns this class. - private final ClientRpcChannel owner; - - // Represents the current call, or null if this is a pending controller. - private RpcState state = null; - - /** - * Package-public constructor, to be invoked by instances of ClientRpcChannel. - */ - ClientRpcController(ClientRpcChannel owner) { - this.owner = owner; - state = null; - } - - /** - * Returns the current status of this class in terms of the {@link Status} - * enum. - */ - Status status() { - return state == null ? Status.PENDING : (state.complete ? Status.COMPLETE : Status.ACTIVE); - } - - /** - * Assert that this controller is in the given status. - */ - private void checkStatus(Status statusToAssert) { - Status currentStatus = status(); - if (!currentStatus.equals(statusToAssert)) { - throw new IllegalStateException("Controller expected status " + statusToAssert + ", was " - + currentStatus); - } - } - - /** - * Configure this RpcController with a new RpcStatus instance. - */ - void configure(RpcState state) { - checkStatus(Status.PENDING); - if (this.state != null) { - throw new IllegalStateException("Can't configure this RPC, already configured."); - } else if (!owner.equals(state.creator)) { - throw new IllegalArgumentException("Should only be configured by " + owner - + ", configuration attempted by " + state.creator); - } - this.state = state; - } - - /** - * Provide a response to this RpcController. Intercepts valid completion - * conditions in order to mark a RPC as complete. Passes through all messages - * to the internal callback for the current RPC invocation. - */ - void response(Message message) { - checkStatus(Status.ACTIVE); - // Any message will complete a normal RPC, whereas only a null message will - // end a streaming RPC. - if (!state.isStreamingRpc) { - if (message == null) { - // The server end-point should not actually allow non-streaming RPCs - // to call back with null messages - we should never get here. - throw new IllegalStateException("Normal RPCs should not be completed early."); - } else { - // Normal RPCs will complete on any valid incoming message. - state.complete = true; - } - } else if (message == null) { - // Complete this streaming RPC with this blank message. - state.complete = true; - } - try { - state.callback.run(message); - } catch (RuntimeException e) { - e.printStackTrace(); - } - } - - /** - * Indicate that the RPC has failed. This requires that the RPC is currently - * active, and marks this RPC as complete. - */ - void failure(String errorText) { - checkStatus(Status.ACTIVE); - state.complete = true; - state.failed = true; - state.errorText = errorText; - - // Hint to the internal callback that this RPC is finished (Normal RPCs - // will always understand this as an error case, whereas streaming RPCs - // will have to check their controller). - state.callback.run(null); - } - - @Override - public String errorText() { - return failed() ? state.errorText : null; - } - - @Override - public boolean failed() { - checkStatus(Status.COMPLETE); - return state.failed; - } - - @Override - public boolean isCanceled() { - throw new UnsupportedOperationException("Server-side method of RpcController only."); - } - - @Override - public void notifyOnCancel(RpcCallback<Object> callback) { - throw new UnsupportedOperationException("Server-side method of RpcController only."); - } - - @Override - public void reset() { - checkStatus(Status.COMPLETE); - state = null; - } - - @Override - public void setFailed(String reason) { - throw new UnsupportedOperationException("Server-side method of RpcController only."); - } - - @Override - public void startCancel() { - Status status = status(); - if (status == Status.PENDING) { - throw new IllegalStateException("Can't cancel this RPC, not currently active."); - } else if (status == Status.COMPLETE) { - // We drop these requests silently - since there is no way for the client - // to know whether the RPC has finished while they are setting up their - // cancellation. - } else { - state.cancelRpc.run(); - } - } -} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/FetchProfilesServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/FetchProfilesServlet.java b/src/org/waveprotocol/box/server/rpc/FetchProfilesServlet.java deleted file mode 100644 index 0033ff5..0000000 --- a/src/org/waveprotocol/box/server/rpc/FetchProfilesServlet.java +++ /dev/null @@ -1,205 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.inject.name.Named; -import com.google.protobuf.MessageLite; -import com.google.wave.api.FetchProfilesRequest; -import com.google.wave.api.FetchProfilesResult; -import com.google.wave.api.JsonRpcConstant.ParamsProperty; -import com.google.wave.api.JsonRpcResponse; -import com.google.wave.api.OperationQueue; -import com.google.wave.api.OperationRequest; -import com.google.wave.api.ParticipantProfile; -import com.google.wave.api.ProtocolVersion; -import com.google.wave.api.data.converter.EventDataConverterManager; - -import org.waveprotocol.box.profile.ProfilesProto.ProfileRequest; -import org.waveprotocol.box.profile.ProfilesProto.ProfileResponse; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.robots.OperationContextImpl; -import org.waveprotocol.box.server.robots.OperationServiceRegistry; -import org.waveprotocol.box.server.robots.util.ConversationUtil; -import org.waveprotocol.box.server.robots.util.OperationUtil; -import org.waveprotocol.box.server.rpc.ProtoSerializer.SerializationException; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.wave.model.wave.ParticipantId; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * A servlet that enables the client side to fetch user profiles using Data API. - * Typically will be hosted on /profile. - * - * Valid request is: GET - * /profile/?addresses=us...@example.com,us...@example.com - in URL encoded - * format. The format of the returned information is the protobuf-JSON format - * used by the websocket interface. - * - * @author yur...@apache.org (Yuri Zelikov) - */ -@SuppressWarnings("serial") -@Singleton -public final class FetchProfilesServlet extends HttpServlet { - - private static final Logger LOG = Logger.getLogger(FetchProfilesServlet.class.getCanonicalName()); - - private final ConversationUtil conversationUtil; - private final EventDataConverterManager converterManager; - private final WaveletProvider waveletProvider; - private final SessionManager sessionManager; - private final OperationServiceRegistry operationRegistry; - private final ProtoSerializer serializer; - - /** - * Extracts profile query params from request. - * - * @param req the request. - * @param response the response. - * @return the ProfileRequest with query data. - * @throws UnsupportedEncodingException if the request parameters encoding is invalid. - */ - private static ProfileRequest parseProfileRequest(HttpServletRequest req, - HttpServletResponse response) throws UnsupportedEncodingException { - String[] addresses = URLDecoder.decode(req.getParameter("addresses"), "UTF-8").split(","); - ProfileRequest profileRequest = - ProfileRequest.newBuilder().addAllAddresses(Lists.newArrayList(addresses)).build(); - return profileRequest; - } - - /** - * Constructs ProfileResponse which is a protobuf generated class from the - * output of Data API profile service. ProfileResponse contains the same - * information as profileResult. - * - * @param profileResult the profile results with digests. - * @return ProfileResponse - */ - private static ProfileResponse serializeProfileResult(FetchProfilesResult profileResult) { - ProfileResponse.Builder builder = ProfileResponse.newBuilder(); - for (ParticipantProfile participantProfile : profileResult.getProfiles()) { - ProfileResponse.FetchedProfile fetchedProfile = - ProfileResponse.FetchedProfile.newBuilder().setAddress(participantProfile.getAddress()) - .setImageUrl(participantProfile.getImageUrl()) - .setName(participantProfile.getName()) - .setProfileUrl(participantProfile.getProfileUrl()).build(); - builder.addProfiles(fetchedProfile); - } - return builder.build(); - } - - @Inject - public FetchProfilesServlet(SessionManager sessionManager, - EventDataConverterManager converterManager, - @Named("DataApiRegistry") OperationServiceRegistry operationRegistry, - WaveletProvider waveletProvider, ConversationUtil conversationUtil, - ProtoSerializer serializer) { - this.converterManager = converterManager; - this.waveletProvider = waveletProvider; - this.conversationUtil = conversationUtil; - this.sessionManager = sessionManager; - this.operationRegistry = operationRegistry; - this.serializer = serializer; - } - - /** - * Creates HTTP response to the profile query. Main entrypoint for this class. - */ - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { - ParticipantId user = sessionManager.getLoggedInUser(req.getSession(false)); - if (user == null) { - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - ProfileRequest profileRequest = parseProfileRequest(req, response); - ProfileResponse profileResponse = fetchProfiles(profileRequest, user); - printJson(profileResponse, response); - } - - /** - * Fetches profile using Data API. - */ - private ProfileResponse fetchProfiles(ProfileRequest profileRequest, ParticipantId user) { - if (LOG.isLoggable(Level.FINE)) { - LOG.fine("Fetching profiles: " + Joiner.on(",").join(profileRequest.getAddressesList())); - } - FetchProfilesResult profileResult = - fetchProfilesFromService(user, profileRequest.getAddressesList()); - LOG.fine("Fetched profiles: " + profileResult.getProfiles().size()); - return serializeProfileResult(profileResult); - } - - /** - * Fetches multiple profiles using Data API. - */ - private FetchProfilesResult fetchProfilesFromService(ParticipantId user, - List<String> addresses) { - OperationQueue opQueue = new OperationQueue(); - FetchProfilesRequest request = new FetchProfilesRequest(addresses); - opQueue.fetchProfiles(request); - OperationContextImpl context = - new OperationContextImpl(waveletProvider, - converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil); - OperationRequest operationRequest = opQueue.getPendingOperations().get(0); - String opId = operationRequest.getId(); - OperationUtil.executeOperation(operationRequest, operationRegistry, context, user); - JsonRpcResponse jsonRpcResponse = context.getResponses().get(opId); - FetchProfilesResult profileResults = - (FetchProfilesResult) jsonRpcResponse.getData().get(ParamsProperty.FETCH_PROFILES_RESULT); - return profileResults; - } - - /** - * Writes the json with profile results to Response. - */ - private void printJson(MessageLite message, HttpServletResponse resp) - throws IOException { - if (message == null) { - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - } else { - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType("application/json"); - // This is to make sure the fetched data is fresh - since the w3c spec - // is rarely respected. - resp.setHeader("Cache-Control", "no-store"); - try { - // FIXME (user) Returning JSON directly from an HTTP GET is vulnerable - // to XSSI attacks. Issue https://issues.apache.org/jira/browse/WAVE-135 - resp.getWriter().append(serializer.toJson(message).toString()); - } catch (SerializationException e) { - throw new IOException(e); - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/FetchServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/FetchServlet.java b/src/org/waveprotocol/box/server/rpc/FetchServlet.java deleted file mode 100644 index 303915c..0000000 --- a/src/org/waveprotocol/box/server/rpc/FetchServlet.java +++ /dev/null @@ -1,188 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.annotations.VisibleForTesting; -import com.google.inject.Inject; -import com.google.protobuf.MessageLite; - -import org.waveprotocol.box.common.comms.WaveClientRpc.DocumentSnapshot; -import org.waveprotocol.box.common.comms.WaveClientRpc.WaveViewSnapshot; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.common.SnapshotSerializer; -import org.waveprotocol.box.server.frontend.CommittedWaveletSnapshot; -import org.waveprotocol.box.server.rpc.ProtoSerializer.SerializationException; -import org.waveprotocol.box.server.waveserver.WaveServerException; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.wave.model.id.ModernIdSerialiser; -import org.waveprotocol.wave.model.id.WaveletId; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; -import org.waveprotocol.wave.model.waveref.InvalidWaveRefException; -import org.waveprotocol.wave.model.waveref.WaveRef; -import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder; -import org.waveprotocol.wave.util.logging.Log; - -import java.io.IOException; - -import javax.inject.Singleton; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * A servlet for static fetching of wave data. Typically, the servlet will be - * hosted on /fetch/*. A document, a wavelet, or a whole wave can be specified - * in the URL. - * - * Valid request formats are: Fetch a wave: GET /fetch/wavedomain.com/waveid - * Fetch a wavelet: GET /fetch/wavedomain.com/waveid/waveletdomain.com/waveletid - * Fetch a document: GET - * /fetch/wavedomain.com/waveid/waveletdomain.com/waveletid/b+abc123 - * - * The format of the returned information is the protobuf-JSON format used by - * the websocket interface. - */ -@SuppressWarnings("serial") -@Singleton -public final class FetchServlet extends HttpServlet { - private static final Log LOG = Log.get(FetchServlet.class); - - @Inject - public FetchServlet( - WaveletProvider waveletProvider, ProtoSerializer serializer, SessionManager sessionManager) { - this.waveletProvider = waveletProvider; - this.serializer = serializer; - this.sessionManager = sessionManager; - } - - private final ProtoSerializer serializer; - private final WaveletProvider waveletProvider; - private final SessionManager sessionManager; - - /** - * Create an http response to the fetch query. Main entrypoint for this class. - */ - @Override - @VisibleForTesting - protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { - ParticipantId user = sessionManager.getLoggedInUser(req.getSession(false)); - - // This path will look like "/example.com/w+abc123/foo.com/conv+root - // Strip off the leading '/'. - String urlPath = req.getPathInfo().substring(1); - - // Extract the name of the wavelet from the URL - WaveRef waveref; - try { - waveref = JavaWaverefEncoder.decodeWaveRefFromPath(urlPath); - } catch (InvalidWaveRefException e) { - // The URL contains an invalid waveref. There's no document at this path. - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - - renderSnapshot(waveref, user, response); - } - - private void serializeObjectToServlet(MessageLite message, HttpServletResponse dest) - throws IOException { - if (message == null) { - // Snapshot is null. It would be nice to 404 here, but we can't let - // clients guess valid wavelet ids that they're not authorized to access. - dest.sendError(HttpServletResponse.SC_FORBIDDEN); - } else { - dest.setStatus(HttpServletResponse.SC_OK); - dest.setContentType("application/json"); - - // This is a hack to make sure the fetched data is fresh. - // TODO(josephg): Change this so that browsers can cache wave snapshots. Probably need: - // 'Cache-Control: must-revalidate, private' and an ETag with the wave[let]'s version. - dest.setHeader("Cache-Control", "no-store"); - - try { - dest.getWriter().append(serializer.toJson(message).toString()); - } catch (SerializationException e) { - throw new IOException(e); - } - } - } - - /** - * Render the requested waveref out to the HttpServletResponse dest. - * - * @param waveref The referenced wave. Could be a whole wave, a wavelet or - * just a document. - * @param dest The servlet response to render the snapshot out to. - * @throws IOException - */ - private void renderSnapshot(WaveRef waveref, ParticipantId requester, HttpServletResponse dest) - throws IOException { - // TODO(josephg): Its currently impossible to fetch all wavelets inside a - // wave that are visible to the user. Until this is fixed, if no wavelet is - // specified we'll just return the conv+root. - WaveletId waveletId = waveref.hasWaveletId() ? waveref.getWaveletId() : WaveletId.of( - waveref.getWaveId().getDomain(), "conv+root"); - - WaveletName waveletName = WaveletName.of(waveref.getWaveId(), waveletId); - - CommittedWaveletSnapshot committedSnapshot; - try { - if (!waveletProvider.checkAccessPermission(waveletName, requester)) { - dest.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - LOG.info("Fetching snapshot of wavelet " + waveletName); - committedSnapshot = waveletProvider.getSnapshot(waveletName); - } catch (WaveServerException e) { - throw new IOException(e); - } - if (committedSnapshot != null) { - ReadableWaveletData snapshot = committedSnapshot.snapshot; - if (waveref.hasDocumentId()) { - // We have a wavelet id and document id. Find the document in the - // snapshot and return it. - DocumentSnapshot docSnapshot = null; - for (String docId : snapshot.getDocumentIds()) { - if (docId.equals(waveref.getDocumentId())) { - docSnapshot = SnapshotSerializer.serializeDocument(snapshot.getDocument(docId)); - break; - } - } - serializeObjectToServlet(docSnapshot, dest); - } else if (waveref.hasWaveletId()) { - // We have a wavelet id. Pull up the wavelet snapshot and return it. - serializeObjectToServlet(SnapshotSerializer.serializeWavelet(snapshot, - snapshot.getHashedVersion()), dest); - } else { - // Wrap the conv+root we fetched earlier in a WaveSnapshot object and - // send it. - WaveViewSnapshot waveSnapshot = WaveViewSnapshot.newBuilder() - .setWaveId(ModernIdSerialiser.INSTANCE.serialiseWaveId(waveref.getWaveId())) - .addWavelet(SnapshotSerializer.serializeWavelet(snapshot, snapshot.getHashedVersion())) - .build(); - serializeObjectToServlet(waveSnapshot, dest); - } - } else { - dest.sendError(HttpServletResponse.SC_FORBIDDEN); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/GadgetProviderServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/GadgetProviderServlet.java b/src/org/waveprotocol/box/server/rpc/GadgetProviderServlet.java deleted file mode 100644 index 9e696ff..0000000 --- a/src/org/waveprotocol/box/server/rpc/GadgetProviderServlet.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; - -import org.waveprotocol.box.server.persistence.file.FileAccountStore; -import org.waveprotocol.box.server.persistence.file.FileUtils; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.inject.Singleton; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * The servlet for fetching available gadgets from a json file on the server. - */ -@SuppressWarnings("serial") -@Singleton -public class GadgetProviderServlet extends HttpServlet { - - private static final Logger LOG = Logger.getLogger(FileAccountStore.class.getName()); - - private final LoadingCache<String, String> jsonCache = CacheBuilder.newBuilder().expireAfterWrite(5, - TimeUnit.MINUTES).build(new CacheLoader<String, String>() { - - public String load(String key) { - String jsonString = ""; - try { - jsonString = FileUtils.getStringFromFile("jsongadgets.json"); - } catch (IOException e) { - LOG.log(Level.WARNING, "Error while loading gadgets json", e); - } - return jsonString; - } - }); - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - try { - String jsonString = jsonCache.get(""); - if (jsonString.equals("")) { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Error loading json data from file"); - } else { - PrintWriter out = response.getWriter(); - out.print(jsonCache.get("")); - out.flush(); - } - } catch (ExecutionException ex) { - throw new IOException(ex); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/LocaleServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/LocaleServlet.java b/src/org/waveprotocol/box/server/rpc/LocaleServlet.java deleted file mode 100644 index ee8dc1c..0000000 --- a/src/org/waveprotocol/box/server/rpc/LocaleServlet.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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.rpc; - -import org.waveprotocol.box.server.persistence.AccountStore; -import org.waveprotocol.box.server.persistence.PersistenceException; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.util.logging.Log; -import org.waveprotocol.box.server.account.HumanAccountData; -import org.waveprotocol.box.server.account.AccountData; -import org.waveprotocol.box.server.account.HumanAccountDataImpl; -import org.waveprotocol.box.server.authentication.SessionManager; - -import com.google.inject.Inject; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.BufferedReader; -import java.io.IOException; -import java.net.URLDecoder; -import javax.inject.Singleton; - -/** - * - * Servlet allows user to store locale. - * - * @author akapla...@gmail.com (Andrew Kaplanov) - */ -@SuppressWarnings("serial") -@Singleton -public final class LocaleServlet extends HttpServlet { - - private final SessionManager sessionManager; - private final AccountStore accountStore; - private final Log LOG = Log.get(LocaleServlet.class); - - @Inject - public LocaleServlet(SessionManager sessionManager, AccountStore accountStore) { - this.sessionManager = sessionManager; - this.accountStore = accountStore; - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { - try { - ParticipantId participant = sessionManager.getLoggedInUser(req.getSession(false)); - if (participant == null) { - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - String locale = URLDecoder.decode(req.getParameter("locale"), "UTF-8"); - AccountData account = accountStore.getAccount(participant); - HumanAccountData humanAccount; - if (account != null) { - humanAccount = account.asHuman(); - } else { - humanAccount = new HumanAccountDataImpl(participant); - } - humanAccount.setLocale(locale); - accountStore.putAccount(humanAccount); - } catch (PersistenceException ex) { - throw new IOException(ex); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/MessageExpectingChannel.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/MessageExpectingChannel.java b/src/org/waveprotocol/box/server/rpc/MessageExpectingChannel.java deleted file mode 100644 index 39998c2..0000000 --- a/src/org/waveprotocol/box/server/rpc/MessageExpectingChannel.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.collect.Maps; -import com.google.protobuf.Message; - -import java.util.Map; - -/** - * Channel superclass to abstract expected-message mechanism. - * - * Note: {@link #expectMessage} has no effect. - */ -public abstract class MessageExpectingChannel { - private final Map<String, Message> expectedMessages = Maps.newHashMap(); - /** - * Register an expected incoming message type. - * - * @param messagePrototype the prototype of the expected type - */ - public void expectMessage(Message messagePrototype) { - expectedMessages.put(messagePrototype.getDescriptorForType().getFullName(), messagePrototype); - } - - public Message getMessagePrototype(String messageType) { - return expectedMessages.get(messageType); - } - - /** - * Send the given message across the connection along with the sequence number. - * - * @param sequenceNo - * @param message - */ - public abstract void sendMessage(int sequenceNo, Message message); - - /** - * Helper method around {{@link #sendMessage(long, Message)} which - * automatically registers the response type as an expected input to this - * SequencedProtoChannel. - * - * @param sequenceNo - * @param message - * @param expectedResponsePrototype - */ - public void sendMessage(int sequenceNo, Message message, Message expectedResponsePrototype) { - expectMessage(expectedResponsePrototype); - sendMessage(sequenceNo, message); - } - - public void startAsyncRead() { - // nothing necessarily to do. - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/NotificationServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/NotificationServlet.java b/src/org/waveprotocol/box/server/rpc/NotificationServlet.java deleted file mode 100644 index f081c04..0000000 --- a/src/org/waveprotocol/box/server/rpc/NotificationServlet.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.annotations.VisibleForTesting; -import com.google.gson.Gson; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.inject.name.Named; -import com.google.wave.api.SearchResult; -import com.google.wave.api.SearchResult.Digest; -import com.google.wave.api.data.converter.EventDataConverterManager; - -import org.waveprotocol.box.search.SearchProto.SearchRequest; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.robots.OperationServiceRegistry; -import org.waveprotocol.box.server.robots.util.ConversationUtil; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.wave.model.wave.ParticipantId; - -import java.io.IOException; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Provides search result digests in JSON format. - * - * @author yur...@apache.org (Yuri Z.) - */ -@SuppressWarnings("serial") -@Singleton -public final class NotificationServlet extends AbstractSearchServlet { - - private static final Gson GSON = new Gson(); - - @Inject - public NotificationServlet(SessionManager sessionManager, - EventDataConverterManager converterManager, - @Named("DataApiRegistry") OperationServiceRegistry operationRegistry, - WaveletProvider waveletProvider, ConversationUtil conversationUtil, ProtoSerializer serializer) { - super(conversationUtil, converterManager, waveletProvider, sessionManager, operationRegistry); - } - - /** - * Creates HTTP response to the search query. Main entrypoint for this class. - */ - @Override - @VisibleForTesting - protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { - ParticipantId user = sessionManager.getLoggedInUser(req.getSession(false)); - if (user == null) { - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - SearchRequest searchRequest = parseSearchRequest(req, response); - SearchResult searchResult = performSearch(searchRequest, user); - serializeObjectToServlet(searchResult.getDigests(), response); - } - - /** - * Writes the json with search results to Response. - */ - private void serializeObjectToServlet(List<Digest> digests, HttpServletResponse resp) - throws IOException { - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType("text/html; charset=utf8"); - // This is to make sure the fetched data is fresh - since the w3c spec - // is rarely respected. - resp.setHeader("Cache-Control", "no-store"); - resp.getWriter().append(GSON.toJson(digests)); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/ProtoCallback.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/ProtoCallback.java b/src/org/waveprotocol/box/server/rpc/ProtoCallback.java deleted file mode 100644 index c79a6e2..0000000 --- a/src/org/waveprotocol/box/server/rpc/ProtoCallback.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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.rpc; - -import com.google.protobuf.Message; - -public interface ProtoCallback { - public void message(int sequenceNo, Message message); -} - http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/ProtoSerializer.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/ProtoSerializer.java b/src/org/waveprotocol/box/server/rpc/ProtoSerializer.java deleted file mode 100644 index 07b8bba..0000000 --- a/src/org/waveprotocol/box/server/rpc/ProtoSerializer.java +++ /dev/null @@ -1,238 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.collect.Maps; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.protobuf.Message; -import com.google.protobuf.MessageLite; - -import org.waveprotocol.box.common.comms.WaveClientRpc.DocumentSnapshot; -import org.waveprotocol.box.common.comms.WaveClientRpc.ProtocolAuthenticate; -import org.waveprotocol.box.common.comms.WaveClientRpc.ProtocolAuthenticationResult; -import org.waveprotocol.box.common.comms.WaveClientRpc.ProtocolOpenRequest; -import org.waveprotocol.box.common.comms.WaveClientRpc.ProtocolSubmitRequest; -import org.waveprotocol.box.common.comms.WaveClientRpc.ProtocolSubmitResponse; -import org.waveprotocol.box.common.comms.WaveClientRpc.ProtocolWaveletUpdate; -import org.waveprotocol.box.common.comms.WaveClientRpc.WaveViewSnapshot; -import org.waveprotocol.box.common.comms.WaveClientRpc.WaveletSnapshot; -import org.waveprotocol.box.common.comms.proto.DocumentSnapshotProtoImpl; -import org.waveprotocol.box.common.comms.proto.ProtocolAuthenticateProtoImpl; -import org.waveprotocol.box.common.comms.proto.ProtocolAuthenticationResultProtoImpl; -import org.waveprotocol.box.common.comms.proto.ProtocolOpenRequestProtoImpl; -import org.waveprotocol.box.common.comms.proto.ProtocolSubmitRequestProtoImpl; -import org.waveprotocol.box.common.comms.proto.ProtocolSubmitResponseProtoImpl; -import org.waveprotocol.box.common.comms.proto.ProtocolWaveletUpdateProtoImpl; -import org.waveprotocol.box.common.comms.proto.WaveViewSnapshotProtoImpl; -import org.waveprotocol.box.common.comms.proto.WaveletSnapshotProtoImpl; -import org.waveprotocol.box.profile.ProfilesProto.ProfileResponse; -import org.waveprotocol.box.profile.proto.ProfileResponseProtoImpl; -import org.waveprotocol.box.search.SearchProto.SearchResponse; -import org.waveprotocol.box.search.proto.SearchResponseProtoImpl; -import org.waveprotocol.box.server.rpc.Rpc.CancelRpc; -import org.waveprotocol.box.server.rpc.Rpc.RpcFinished; -import org.waveprotocol.box.server.rpc.proto.CancelRpcProtoImpl; -import org.waveprotocol.box.server.rpc.proto.RpcFinishedProtoImpl; -import org.waveprotocol.box.attachment.AttachmentProto.AttachmentsResponse; -import org.waveprotocol.box.attachment.proto.AttachmentsResponseProtoImpl; -import org.waveprotocol.wave.communication.gson.GsonException; -import org.waveprotocol.wave.communication.gson.GsonSerializable; -import org.waveprotocol.wave.communication.json.RawStringData; -import org.waveprotocol.wave.communication.proto.ProtoWrapper; - -import java.util.Map; - -/** - * Serializes protos to/from JSON objects. - * <p> - * This class uses the PST-generated message classes to perform serialization - * and deserialization. - */ -public final class ProtoSerializer { - - public static final class SerializationException extends Exception { - public SerializationException(Exception cause) { - super(cause); - } - - public SerializationException(String message) { - super(message); - } - } - - /** - * Serializes protos of a particular type to/from JSON objects. - * - * @param <P> proto type - * @param <D> GSON-based DTO wrapper type for a {@code P} - */ - static final class ProtoImplSerializer< - P extends Message, - D extends ProtoWrapper<P> & GsonSerializable> { - private final Class<P> protoClass; - private final Class<D> dtoClass; - - ProtoImplSerializer(Class<P> protoClass, Class<D> dtoClass) { - this.protoClass = protoClass; - this.dtoClass = dtoClass; - } - - static <P extends Message, D extends ProtoWrapper<P> & GsonSerializable> - ProtoImplSerializer<P, D> of( - Class<P> protoClass, Class<D> dtoClass) { - return new ProtoImplSerializer<P, D>(protoClass, dtoClass); - } - - D newDto() throws SerializationException { - try { - return dtoClass.newInstance(); - } catch (InstantiationException e) { - throw new SerializationException(e); - } catch (IllegalAccessException e) { - throw new SerializationException(e); - } - } - - JsonElement toGson(MessageLite proto, RawStringData data, Gson gson) - throws SerializationException { - Preconditions.checkState(protoClass.isInstance(proto)); - D dto = newDto(); - dto.setPB(protoClass.cast(proto)); - return dto.toGson(data, gson); - } - - P fromJson(JsonElement json, RawStringData data, Gson gson) throws SerializationException { - D dto = newDto(); - try { - dto.fromGson(json, gson, data); - } catch (GsonException e) { - throw new SerializationException(e); - } - return dto.getPB(); - } - } - - private final Gson gson = new Gson(); - private final Map<Class<?>, ProtoImplSerializer<?, ?>> byClass = Maps.newHashMap(); - private final Map<String, ProtoImplSerializer<?, ?>> byName = Maps.newHashMap(); - - public ProtoSerializer() { - init(); - } - - /** Adds the known proto types. */ - private void init() { - // Note: this list is too inclusive, but has historically always been so. - // The real list only needs about 5 protos, since only top-level rpc types - // need to be here, not every single recursively reachable proto. - add(ProtocolAuthenticate.class, ProtocolAuthenticateProtoImpl.class); - add(ProtocolAuthenticationResult.class, ProtocolAuthenticationResultProtoImpl.class); - add(ProtocolOpenRequest.class, ProtocolOpenRequestProtoImpl.class); - add(ProtocolSubmitRequest.class, ProtocolSubmitRequestProtoImpl.class); - add(ProtocolSubmitResponse.class, ProtocolSubmitResponseProtoImpl.class); - add(ProtocolWaveletUpdate.class, ProtocolWaveletUpdateProtoImpl.class); - add(WaveletSnapshot.class, WaveletSnapshotProtoImpl.class); - add(DocumentSnapshot.class, DocumentSnapshotProtoImpl.class); - add(WaveViewSnapshot.class, WaveViewSnapshotProtoImpl.class); - - add(CancelRpc.class, CancelRpcProtoImpl.class); - add(RpcFinished.class, RpcFinishedProtoImpl.class); - - add(SearchResponse.class, SearchResponseProtoImpl.class); - add(ProfileResponse.class, ProfileResponseProtoImpl.class); - - add(AttachmentsResponse.class, AttachmentsResponseProtoImpl.class); - } - - /** Adds a binding between a proto class and a DTO message class. */ - private <P extends Message, D extends ProtoWrapper<P> & GsonSerializable> void add( - Class<P> protoClass, Class<D> dtoClass) { - ProtoImplSerializer<P, D> serializer = ProtoImplSerializer.of(protoClass, dtoClass); - byClass.put(protoClass, serializer); - byName.put(protoClass.getSimpleName(), serializer); - } - - /** - * Gets the serializer for a proto class. Never returns null. - * - * @throws SerializationException if there is no serializer for - * {@code protoClass}. - */ - private <P> ProtoImplSerializer<? extends P, ?> getSerializer(Class<P> protoClass) - throws SerializationException { - @SuppressWarnings("unchecked") - // use of serializers map is safe. - ProtoImplSerializer<? extends P, ?> serializer = - (ProtoImplSerializer<? extends P, ?>) byClass.get(protoClass); - if (serializer == null) { - throw new SerializationException("Unknown proto class: " + protoClass.getName()); - } - return serializer; - } - - /** - * Gets the serializer for a proto class name. Never returns null. - * - * @throws SerializationException if there is no serializer for - * {@code protoName}. - */ - private <P extends Message> ProtoImplSerializer<P, ?> getSerializer(String protoName) - throws SerializationException { - @SuppressWarnings("unchecked") - // use of serializers map is safe. - ProtoImplSerializer<P, ?> serializer = (ProtoImplSerializer<P, ?>) byName.get(protoName); - if (serializer == null) { - throw new SerializationException("Unknown proto class: " + protoName); - } - return serializer; - } - - /** - * Serializes a proto to JSON. Only protos whose classes have been registered - * will be serialized. - * - * @throws SerializationException if the class of {@code message} has not been - * registered. - */ - public JsonElement toJson(MessageLite message) throws SerializationException { - return getSerializer(message.getClass()).toGson(message, null, gson); - } - - /** - * Deserializes a proto from JSON. Only protos whose classes have been - * registered can be deserialized. - * - * @throws SerializationException if no class called {@code type} has been - * registered. - */ - public Message fromJson(JsonElement json, String type) throws SerializationException { - return getSerializer(type).fromJson(json, null, gson); - } - - // Utility method for a test. - @VisibleForTesting - public <P extends Message> P fromJson(JsonElement json, Class<P> clazz) - throws SerializationException { - return getSerializer(clazz).fromJson(json, null, gson); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/SearchServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/SearchServlet.java b/src/org/waveprotocol/box/server/rpc/SearchServlet.java deleted file mode 100644 index b4c1252..0000000 --- a/src/org/waveprotocol/box/server/rpc/SearchServlet.java +++ /dev/null @@ -1,177 +0,0 @@ -/** - * 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.rpc; - -import com.google.common.annotations.VisibleForTesting; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.inject.name.Named; -import com.google.protobuf.MessageLite; -import com.google.wave.api.SearchResult; -import com.google.wave.api.SearchResult.Digest; -import com.google.wave.api.data.converter.EventDataConverterManager; - -import org.waveprotocol.box.search.SearchProto.SearchRequest; -import org.waveprotocol.box.search.SearchProto.SearchResponse; -import org.waveprotocol.box.search.SearchProto.SearchResponse.Builder; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.robots.OperationServiceRegistry; -import org.waveprotocol.box.server.robots.util.ConversationUtil; -import org.waveprotocol.box.server.rpc.ProtoSerializer.SerializationException; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.box.stat.Timed; -import org.waveprotocol.box.webclient.search.SearchService; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.util.logging.Log; - -import java.io.IOException; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * A servlet to provide search functionality by using Data API. Typically will - * be hosted on /search. - * - * Valid request format is: GET /search/?query=in:inbox&index=0&numResults=50. - * The format of the returned information is the protobuf-JSON format used by - * the websocket interface. - * - * @author vega...@gmail.com (Yuri Z.) - */ -@SuppressWarnings("serial") -@Singleton -public class SearchServlet extends AbstractSearchServlet { - - private static final Log LOG = Log.get(SearchServlet.class); - - private final ProtoSerializer serializer; - - /** - * Constructs SearchResponse which is a protobuf generated class from the - * output of Data API search service. SearchResponse contains the same - * information as searchResult. - * - * @param searchResult the search results with digests. - * @return SearchResponse - */ - public static SearchResponse serializeSearchResult(SearchResult searchResult, int total) { - Builder searchBuilder = SearchResponse.newBuilder(); - searchBuilder.setQuery(searchResult.getQuery()).setTotalResults(total); - for (SearchResult.Digest searchResultDigest : searchResult.getDigests()) { - SearchResponse.Digest digest = serializeDigest(searchResultDigest); - searchBuilder.addDigests(digest); - } - SearchResponse searchResponse = searchBuilder.build(); - return searchResponse; - } - - /** - * Copies data from {@link Digest} into {@link SearchResponse.Digest}. - */ - private static SearchResponse.Digest serializeDigest(Digest searchResultDigest) { - SearchResponse.Digest.Builder digestBuilder = SearchResponse.Digest.newBuilder(); - digestBuilder.setBlipCount(searchResultDigest.getBlipCount()); - digestBuilder.setLastModified(searchResultDigest.getLastModified()); - digestBuilder.setSnippet(searchResultDigest.getSnippet()); - digestBuilder.setTitle(searchResultDigest.getTitle()); - digestBuilder.setUnreadCount(searchResultDigest.getUnreadCount()); - digestBuilder.setWaveId(searchResultDigest.getWaveId()); - List<String> participants = searchResultDigest.getParticipants(); - if (participants.isEmpty()) { - // This shouldn't be possible. - digestBuilder.setAuthor("nob...@example.com"); - } else { - digestBuilder.setAuthor(participants.get(0)); - for (int i = 1; i < participants.size(); i++) { - digestBuilder.addParticipants(participants.get(i)); - } - } - SearchResponse.Digest digest = digestBuilder.build(); - return digest; - } - - @Inject - public SearchServlet(SessionManager sessionManager, EventDataConverterManager converterManager, - @Named("DataApiRegistry") OperationServiceRegistry operationRegistry, - WaveletProvider waveletProvider, ConversationUtil conversationUtil, ProtoSerializer serializer) { - super(conversationUtil, converterManager, waveletProvider, sessionManager, operationRegistry); - this.serializer = serializer; - } - - /** - * Creates HTTP response to the search query. Main entrypoint for this class. - */ - @Timed - @Override - @VisibleForTesting - protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { - ParticipantId user = sessionManager.getLoggedInUser(req.getSession(false)); - if (user == null) { - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - SearchRequest searchRequest = parseSearchRequest(req, response); - SearchResult searchResult = performSearch(searchRequest, user); - - int totalGuess = computeTotalResultsNumberGuess(searchRequest, searchResult); - LOG.fine("Results: " + searchResult.getNumResults() + ", total: " + totalGuess); - SearchResponse searchResponse = serializeSearchResult(searchResult, totalGuess); - serializeObjectToServlet(searchResponse, response); - } - - private int computeTotalResultsNumberGuess(SearchRequest searchRequest, SearchResult searchResult) { - // The Data API does not return the total size of the search result, even - // though the searcher knows it. The only approximate knowledge that can be - // gleaned from the Data API is whether there are more search results beyond - // those returned. If the searcher returns as many (or more) results as - // requested, then assume that more results exist, but the total is unknown. - // Otherwise, the total has been reached. - int totalGuess; - if (searchResult.getNumResults() >= searchRequest.getNumResults()) { - totalGuess = SearchService.UNKNOWN_SIZE; - } else { - totalGuess = searchRequest.getIndex() + searchResult.getNumResults(); - } - return totalGuess; - } - - /** - * Writes the json with search results to Response. - */ - private void serializeObjectToServlet(MessageLite message, HttpServletResponse resp) - throws IOException { - if (message == null) { - resp.sendError(HttpServletResponse.SC_FORBIDDEN); - } else { - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType("application/json; charset=utf8"); - // This is to make sure the fetched data is fresh - since the w3c spec - // is rarely respected. - resp.setHeader("Cache-Control", "no-store"); - try { - resp.getWriter().append(serializer.toJson(message).toString()); - } catch (SerializationException e) { - throw new IOException(e); - } - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/ServerRpcController.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/ServerRpcController.java b/src/org/waveprotocol/box/server/rpc/ServerRpcController.java deleted file mode 100644 index 80ee184..0000000 --- a/src/org/waveprotocol/box/server/rpc/ServerRpcController.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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.rpc; - -import com.google.protobuf.RpcController; - -import org.waveprotocol.wave.model.wave.ParticipantId; - -/** - * Extends RpcController to include additional state wave in a box requires. - * - * @author jose...@gmail.com (Joseph Gentle) - */ -public interface ServerRpcController extends RpcController, Runnable { - /** - * Get the currently logged in user - * - * @return the currently logged in user, or null. - */ - ParticipantId getLoggedInUser(); - - /** - * Mark this controller as cancelled, i.e., as the result of a client request. - * Call the pending cancellation callback, if there is one. - */ - void cancel(); -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/ServerRpcControllerImpl.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/ServerRpcControllerImpl.java b/src/org/waveprotocol/box/server/rpc/ServerRpcControllerImpl.java deleted file mode 100644 index 79395da..0000000 --- a/src/org/waveprotocol/box/server/rpc/ServerRpcControllerImpl.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * 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.rpc; - -import com.google.protobuf.Descriptors; -import com.google.protobuf.Message; -import com.google.protobuf.RpcCallback; -import com.google.protobuf.Service; - -import org.waveprotocol.wave.model.wave.ParticipantId; - -/** - * Implements the server end-point of a wave server RPC connection. This is a - * single-use RPC controller. - * - * - */ -public class ServerRpcControllerImpl implements ServerRpcController { - private final Message requestMessage; - private final Service backingService; - private final Descriptors.MethodDescriptor serviceMethod; - private final RpcCallback<Message> callback; - private final boolean isStreamingRpc; - - // The following variables represent the current status of this instance, and - // must all only be accessed or modified while synchronised on statusLock. - private final Object statusLock = new Object(); - private boolean complete = false; - private RpcCallback<Object> cancelCallback = null; - private boolean cancelled = false; - private final ParticipantId loggedInUser; - - /** - * Instantiate a new ServerRpcController that may later be completely invoked - * by calling {#link run}. - * - * @param requestMessage the request being handled - * @param backingService the backing service type - * @param serviceMethod the specific method within the backing service type - * @param loggedInUser the currently logged in user - * @param callback the destination where responses may be passed - may be - * called once (normal RPC) or 1-n times (streaming RPC), and will pass - * instances of RpcFinished as required (error cases, or streaming RPC - * shutdown); is also always called under the ServerRpcController's - * statusLock to ensure that consecutive calls (in the streaming case) - * are called in series - */ - ServerRpcControllerImpl(Message requestMessage, Service backingService, - Descriptors.MethodDescriptor serviceMethod, ParticipantId loggedInUser, RpcCallback<Message> callback) { - this.requestMessage = requestMessage; - this.backingService = backingService; - this.serviceMethod = serviceMethod; - this.loggedInUser = loggedInUser; - this.isStreamingRpc = serviceMethod.getOptions().getExtension(Rpc.isStreamingRpc); - this.callback = callback; - } - - @Override - public String errorText() { - throw new UnsupportedOperationException("Client-side method of RpcController only."); - } - - @Override - public boolean failed() { - throw new UnsupportedOperationException("Client-side method of RpcController only."); - } - - @Override - public boolean isCanceled() { - return cancelled; - } - - /** - * Registers a cancellation callback. This will always be called as part of - * this RPC, and always at most once; either when the client asks to cancel - * it, or when the RPC finishes (regardless of error case). - * - * This callback will be called outside normal locks on ServerRpcController - * state, i.e., not within a block synchronised on statusLock. - */ - @Override - public void notifyOnCancel(final RpcCallback<Object> callback) { - RpcCallback<Object> runCallback = null; - synchronized (statusLock) { - if (cancelCallback != null) { - throw new IllegalStateException("Must only be called once per request."); - } else { - cancelCallback = callback; - if (cancelled || complete) { - runCallback = cancelCallback; - } - } - } - if (runCallback != null) { - runCallback.run(null); - } - } - - @Override - public void reset() { - throw new UnsupportedOperationException("Client-side method of RpcController only."); - } - - @Override - public void setFailed(String reason) { - RpcCallback<Object> runCallback = null; - synchronized (statusLock) { - if (complete) { - throw new IllegalStateException("Can't fail this RPC, as it is already complete."); - } else { - complete = true; - callback.run(Rpc.RpcFinished.newBuilder().setFailed(true).setErrorText(reason).build()); - if (cancelCallback != null && !cancelled) { - runCallback = cancelCallback; - } - } - } - if (runCallback != null) { - runCallback.run(null); - } - } - - @Override - public void startCancel() { - throw new UnsupportedOperationException("Client-side method of RpcController only."); - } - - @Override - public void cancel() { - RpcCallback<Object> runCallback = null; - synchronized (statusLock) { - if (cancelled) { - throw new IllegalStateException("Can't cancel RPC, already cancelled."); - } - cancelled = true; - if (cancelCallback != null && !complete) { - runCallback = cancelCallback; - } - } - if (runCallback != null) { - runCallback.run(null); - } - } - - /** - * Run this ServerRpcController in the current thread. This must only be - * invoked ONCE, and will throw an IllegalStateException otherwise. - */ - @Override - public void run() { - RpcCallback<Message> messageCallback = new RpcCallback<Message>() { - @Override - public void run(Message result) { - RpcCallback<Object> runCallback = null; - synchronized (statusLock) { - if (complete) { - throw new IllegalStateException("Can't send responses over this RPC, as it is" - + " already complete: " + result); - } - if (!isStreamingRpc || result == null) { - // This either completes the streaming RPC (by passing an instance - // of RpcFinished in place of null) or completes a normal RPC (by - // passing any other message). - if (result == null) { - result = Rpc.RpcFinished.newBuilder().setFailed(false).build(); - } - callback.run(result); - - // Now complete, mark as such and invoke the cancellation callback. - complete = true; - if (cancelCallback != null && !cancelled) { - runCallback = cancelCallback; - } - } else { - // Streaming RPC update. - callback.run(result); - } - } - if (runCallback != null) { - runCallback.run(null); - } - } - }; - try { - backingService.callMethod(serviceMethod, this, requestMessage, messageCallback); - } catch (RuntimeException e) { - // Pass the description of any RuntimeException back to the caller. - e.printStackTrace(); - if (!complete) { - setFailed(e.toString()); - } - } - } - - @Override - public ParticipantId getLoggedInUser() { - return loggedInUser; - } -}