http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/register/RobotRegistrar.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/register/RobotRegistrar.java b/src/org/waveprotocol/box/server/robots/register/RobotRegistrar.java deleted file mode 100644 index fa7efbe..0000000 --- a/src/org/waveprotocol/box/server/robots/register/RobotRegistrar.java +++ /dev/null @@ -1,86 +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.robots.register; - -import org.waveprotocol.box.server.account.RobotAccountData; -import org.waveprotocol.box.server.persistence.PersistenceException; -import org.waveprotocol.box.server.robots.util.RobotsUtil.RobotRegistrationException; -import org.waveprotocol.wave.model.wave.ParticipantId; - -/** - * Provides robot un/registration services. - * - * @author [email protected] (Yuri Zelikov) - */ -public interface RobotRegistrar { - - /** Receives robot un/registration events. */ - public interface Listener { - - /** Invoked after the robot account was created and added to the account store. */ - public void onRegistrationSuccess(RobotAccountData account); - - /** Invoked after the robot account was removed from the account store. */ - public void onUnregistrationSuccess(RobotAccountData account); - } - - /** - * Registers a new robot account. - * - * @param robotId the robotId to register. - * @param location the location of the robot (URI). - * @return the newly registered robot account. - * @throws RobotRegistrationException if account for this id already exist. - * @throws PersistenceException if the persistence layer reports an error. - */ - public RobotAccountData registerNew(ParticipantId robotId, String location) - throws RobotRegistrationException, PersistenceException; - - /** - * Unregisters a robot by removing it from the account store. - * - * @param robotId the id to remove. - * @return the account data of the removed robot or - * <code>null</null> if no such robot account exist. - * @throws RobotRegistrationException if the id to remove exist but is not a - * robot. - * @throws PersistenceException if the persistence layer reports an error. - */ - public RobotAccountData unregister(ParticipantId robotId) throws RobotRegistrationException, - PersistenceException; - - /** - * Registers a new robot or re-registers an existing robot in order to update the robot location. - * - * @param robotId the robot id. - * @param location the new location of the robot (URI). - * @return the updated robot account. - * @throws RobotRegistrationException if the id to re-register exist but is not a robot. - * @throws PersistenceException if the persistence layer reports an error. - */ - public RobotAccountData registerOrUpdate(ParticipantId robotId, String location) - throws RobotRegistrationException, PersistenceException; - - /** Adds listener. */ - public void addRegistrationListener(Listener listener); - - /** Removes listener. */ - public void removeRegistrationListener(Listener listener); -}
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/register/RobotRegistrarImpl.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/register/RobotRegistrarImpl.java b/src/org/waveprotocol/box/server/robots/register/RobotRegistrarImpl.java deleted file mode 100644 index 06b00eb..0000000 --- a/src/org/waveprotocol/box/server/robots/register/RobotRegistrarImpl.java +++ /dev/null @@ -1,218 +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.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 [email protected] (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); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/testing/OperationServiceHelper.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/testing/OperationServiceHelper.java b/src/org/waveprotocol/box/server/robots/testing/OperationServiceHelper.java deleted file mode 100644 index 814f972..0000000 --- a/src/org/waveprotocol/box/server/robots/testing/OperationServiceHelper.java +++ /dev/null @@ -1,120 +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.robots.testing; - -import static org.mockito.Mockito.mock; - -import com.google.wave.api.data.converter.EventDataConverter; -import com.google.wave.api.data.converter.v22.EventDataConverterV22; - -import org.waveprotocol.box.server.robots.OperationContextImpl; -import org.waveprotocol.box.server.robots.RobotWaveletData; -import org.waveprotocol.box.server.robots.operations.OperationService; -import org.waveprotocol.box.server.robots.util.ConversationUtil; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.wave.model.conversation.ObservableConversation; -import org.waveprotocol.wave.model.conversation.WaveletBasedConversation; -import org.waveprotocol.wave.model.id.IdURIEncoderDecoder; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.operation.SilentOperationSink; -import org.waveprotocol.wave.model.operation.wave.BasicWaveletOperationContextFactory; -import org.waveprotocol.wave.model.operation.wave.WaveletOperation; -import org.waveprotocol.wave.model.testing.BasicFactories; -import org.waveprotocol.wave.model.testing.FakeIdGenerator; -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.model.wave.ParticipationHelper; -import org.waveprotocol.wave.model.wave.data.DocumentFactory; -import org.waveprotocol.wave.model.wave.data.DocumentOperationSink; -import org.waveprotocol.wave.model.wave.data.ObservableWaveletData; -import org.waveprotocol.wave.model.wave.data.WaveletData; -import org.waveprotocol.wave.model.wave.data.impl.EmptyWaveletSnapshot; -import org.waveprotocol.wave.model.wave.data.impl.WaveletDataImpl; -import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet; -import org.waveprotocol.wave.util.escapers.jvm.JavaUrlCodec; - -/** - * Helper for testing {@link OperationService}. Puts a single empty - * conversational wavelet with one participant in the operation context. - * - * @author [email protected] (Lennard de Rijk) - */ -public class OperationServiceHelper { - - private static final IdURIEncoderDecoder URI_CODEC = - new IdURIEncoderDecoder(new JavaUrlCodec()); - private static final HashedVersionFactory HASH_FACTORY = new HashedVersionFactoryImpl(URI_CODEC); - private static final DocumentFactory<? extends DocumentOperationSink> DOCUMENT_FACTORY = - BasicFactories.observablePluggableMutableDocumentFactory(); - - private final WaveletProvider waveletProvider; - private final OperationContextImpl context; - - /** - * Constructs a new {@link OperationServiceHelper} with a wavelet with the - * name and participant that are passed in. - * - * @param waveletName the name of the empty wavelet to open in the context. - * @param participant the participant that should be on that empty wavelet. - */ - public OperationServiceHelper(WaveletName waveletName, ParticipantId participant) { - waveletProvider = mock(WaveletProvider.class); - EventDataConverter converter = new EventDataConverterV22(); - - ObservableWaveletData waveletData = WaveletDataImpl.Factory.create(DOCUMENT_FACTORY).create( - new EmptyWaveletSnapshot(waveletName.waveId, waveletName.waveletId, participant, - HASH_FACTORY.createVersionZero(waveletName), 0L)); - waveletData.addParticipant(participant); - - BasicWaveletOperationContextFactory CONTEXT_FACTORY = - new BasicWaveletOperationContextFactory(participant); - - SilentOperationSink<WaveletOperation> executor = - SilentOperationSink.Executor.<WaveletOperation, WaveletData>build(waveletData); - OpBasedWavelet wavelet = - new OpBasedWavelet(waveletData.getWaveId(), waveletData, CONTEXT_FACTORY, - ParticipationHelper.DEFAULT, executor, SilentOperationSink.VOID); - - // Make a conversation with an empty root blip - WaveletBasedConversation.makeWaveletConversational(wavelet); - ConversationUtil conversationUtil = new ConversationUtil(FakeIdGenerator.create()); - ObservableConversation conversation = conversationUtil.buildConversation(wavelet).getRoot(); - conversation.getRootThread().appendBlip(); - - context = new OperationContextImpl(waveletProvider, converter, conversationUtil); - context.putWavelet(waveletName.waveId, waveletName.waveletId, - new RobotWaveletData(waveletData, HASH_FACTORY.createVersionZero(waveletName))); - } - - /** - * @return the {@link WaveletProvider} mock - */ - public WaveletProvider getWaveletProvider() { - return waveletProvider; - } - - /** - * @return the {@link OperationContextImpl} with the empty wavelet opened. - */ - public OperationContextImpl getContext() { - return context; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/util/ConversationUtil.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/util/ConversationUtil.java b/src/org/waveprotocol/box/server/robots/util/ConversationUtil.java deleted file mode 100644 index a3b5ff7..0000000 --- a/src/org/waveprotocol/box/server/robots/util/ConversationUtil.java +++ /dev/null @@ -1,89 +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.robots.util; - -import com.google.common.base.Preconditions; -import com.google.inject.Inject; - -import org.waveprotocol.wave.model.conversation.Conversation; -import org.waveprotocol.wave.model.conversation.ConversationBlip; -import org.waveprotocol.wave.model.conversation.ObservableConversationView; -import org.waveprotocol.wave.model.conversation.WaveBasedConversationView; -import org.waveprotocol.wave.model.conversation.WaveletBasedConversation; -import org.waveprotocol.wave.model.id.IdGenerator; -import org.waveprotocol.wave.model.id.IdUtil; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.wave.ObservableWavelet; -import org.waveprotocol.wave.model.wave.ReadOnlyWaveView; - -/** - * Utility class for {@link Conversation}s used by the Robot API. - * - * @author [email protected] (Lennard de Rijk) - */ -public class ConversationUtil { - - private final IdGenerator idGenerator; - - @Inject - public ConversationUtil(IdGenerator idGenerator) { - this.idGenerator = idGenerator; - } - - /** - * Builds an {@link ObservableConversationView} for the given wavelet. Note - * that this can be expensive since the conversation is not garbage collected - * until the wavelet is. - * - * @param wavelet The wavelet to return the conversation for, must be a valid - * conversation wavelet. - * @throws IllegalArgumentException if the wavelet is not a valid conversation - * wavelet. - */ - public ObservableConversationView buildConversation(ObservableWavelet wavelet) { - Preconditions.checkArgument(IdUtil.isConversationalId(wavelet.getId()), - "Expected conversational wavelet, got " + wavelet.getId()); - Preconditions.checkArgument(WaveletBasedConversation.waveletHasConversation(wavelet), - "Conversation can't be build on a wavelet " + wavelet.getId() - + " without conversation structure"); - - ReadOnlyWaveView wv = new ReadOnlyWaveView(wavelet.getWaveId()); - wv.addWavelet(wavelet); - - return WaveBasedConversationView.create(wv, idGenerator); - } - - /** - * Generates a {@link WaveletName} for a conversational wavelet. - */ - public WaveletName generateWaveletName() { - return WaveletName.of(idGenerator.newWaveId(), idGenerator.newConversationRootWaveletId()); - } - - /** - * Returns the blip id of the first blip in the root thread. - * - * @param conversation the conversation to get the blip id from. - */ - public static String getRootBlipId(Conversation conversation) { - ConversationBlip rootBlip = conversation.getRootThread().getFirstBlip(); - return (rootBlip != null) ? rootBlip.getId() : ""; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/util/LoggingRequestListener.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/util/LoggingRequestListener.java b/src/org/waveprotocol/box/server/robots/util/LoggingRequestListener.java deleted file mode 100644 index e7586e4..0000000 --- a/src/org/waveprotocol/box/server/robots/util/LoggingRequestListener.java +++ /dev/null @@ -1,56 +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.robots.util; - -import org.waveprotocol.box.server.waveserver.WaveletProvider.SubmitRequestListener; -import org.waveprotocol.wave.model.version.HashedVersion; -import org.waveprotocol.wave.util.logging.Log; - -/** - * {@link SubmitRequestListener} that simply logs its calls. - * - * @author [email protected] (Lennard de Rijk) - */ -public final class LoggingRequestListener implements SubmitRequestListener { - - private final Log log; - - /** - * Constructs a new {@link SubmitRequestListener} that logs its calls to the - * given log. - * - * @param log the log to use. - */ - public LoggingRequestListener(Log log) { - this.log = log; - } - - @Override - public void onFailure(String errorMessage) { - log.warning("Robot operations failed to be submitted: " + errorMessage); - } - - @Override - public void onSuccess(int operationsApplied, HashedVersion hashedVersionAfterApplication, - long applicationTimestamp) { - log.fine(operationsApplied + " Robot operations have been succesfully applied " - + "changing the version to " + hashedVersionAfterApplication); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/util/OperationUtil.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/util/OperationUtil.java b/src/org/waveprotocol/box/server/robots/util/OperationUtil.java deleted file mode 100644 index a0c12df..0000000 --- a/src/org/waveprotocol/box/server/robots/util/OperationUtil.java +++ /dev/null @@ -1,301 +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.robots.util; - -import com.google.common.base.Strings; -import com.google.wave.api.ApiIdSerializer; -import com.google.wave.api.InvalidRequestException; -import com.google.wave.api.JsonRpcConstant.ParamsProperty; -import com.google.wave.api.OperationRequest; -import com.google.wave.api.OperationType; -import com.google.wave.api.ProtocolVersion; -import com.google.wave.api.robot.RobotName; - -import org.waveprotocol.box.server.common.CoreWaveletOperationSerializer; -import org.waveprotocol.box.server.robots.OperationContext; -import org.waveprotocol.box.server.robots.OperationResults; -import org.waveprotocol.box.server.robots.OperationServiceRegistry; -import org.waveprotocol.box.server.robots.RobotWaveletData; -import org.waveprotocol.box.server.robots.operations.OperationService; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.box.server.waveserver.WaveletProvider.SubmitRequestListener; -import org.waveprotocol.wave.federation.Proto.ProtocolWaveletDelta; -import org.waveprotocol.wave.model.conversation.ConversationView; -import org.waveprotocol.wave.model.id.IdUtil; -import org.waveprotocol.wave.model.id.InvalidIdException; -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.operation.wave.WaveletDelta; -import org.waveprotocol.wave.model.supplement.PrimitiveSupplement; -import org.waveprotocol.wave.model.supplement.SupplementedWave; -import org.waveprotocol.wave.model.supplement.SupplementedWaveImpl; -import org.waveprotocol.wave.model.supplement.SupplementedWaveImpl.DefaultFollow; -import org.waveprotocol.wave.model.supplement.WaveletBasedSupplement; -import org.waveprotocol.wave.model.wave.InvalidParticipantAddress; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet; -import org.waveprotocol.wave.util.logging.Log; - -import java.util.List; -import java.util.Map.Entry; - -/** - * {@link OperationRequest} utility methods. - * - * @author [email protected] (Lennard de Rijk) - */ -public class OperationUtil { - - private static final Log LOG = Log.get(OperationUtil.class); - - private OperationUtil() { - } - - /** - * Attempts to get a parameter, throws an exception if not found. - * - * @param <T> type of class to cast to. - * @param operation operation to extract property from. - * @param property the key of the parameter. - * @return specialized object after being serialized. - * - * @throws InvalidRequestException if the property is not found. - */ - @SuppressWarnings("unchecked") - public static <T> T getRequiredParameter(OperationRequest operation, ParamsProperty property) - throws InvalidRequestException { - Object parameter = operation.getParameter(property); - Class<T> clazz = (Class<T>) property.clazz(); - if (parameter == null || !clazz.isInstance(parameter)) { - throw new InvalidRequestException("property " + property + " not found", operation); - } - return clazz.cast(parameter); - } - - /** - * Attempts to get a parameter, returns the {@code null} if not found. - * - * @param <T> type of class to cast to. - * @param operation operation to extract property from. - * @param key the key of the parameter. - * @return specialized object after being serialized, or {@code null} if the - * parameter could not be found. - */ - public static <T> T getOptionalParameter(OperationRequest operation, ParamsProperty key) { - return OperationUtil.<T> getOptionalParameter(operation, key, null); - } - - /** - * Attempts to get a parameter, returns the default if not found. - * - * @param <T> type of class to cast to. - * @param operation operation to extract property from. - * @param property the key of the parameter. - * @param defaultValue default value to return if parameter could not be - * found. - * @return specialized object after being serialized, or the default value if - * the parameter could not be found. - */ - @SuppressWarnings("unchecked") - public static <T> T getOptionalParameter( - OperationRequest operation, ParamsProperty property, T defaultValue) { - Object parameter = operation.getParameter(property); - Class<T> clazz = (Class<T>) property.clazz(); - if (parameter != null && clazz.isInstance(parameter)) { - return clazz.cast(parameter); - } - return defaultValue; - } - - /** - * Determines the protocol version of a given operation bundle by inspecting - * the first operation in the bundle. If it is a {@code robot.notify} - * operation, and contains {@code protocolVersion} parameter, then this method - * will return the value of that parameter. Otherwise, this method will return - * the default version. - * - * @param operations the {@link OperationRequest}s to inspect. - * @return the wire protocol version of the given operation bundle. - */ - public static ProtocolVersion getProtocolVersion(List<OperationRequest> operations) { - if (operations.size() == 0) { - return ProtocolVersion.DEFAULT; - } - - OperationRequest firstOperation = operations.get(0); - if (firstOperation.getMethod().equals(OperationType.ROBOT_NOTIFY.method())) { - String versionString = (String) firstOperation.getParameter(ParamsProperty.PROTOCOL_VERSION); - if (versionString != null) { - return ProtocolVersion.fromVersionString(versionString); - } - } - return ProtocolVersion.DEFAULT; - } - - /** - * @return the type of operation present in the request - */ - public static OperationType getOperationType(OperationRequest operation) { - String methodName = operation.getMethod(); - - // TODO(ljvderijk): This might be removed after the deserialization is fixed - if (methodName.startsWith("wave.")) { - methodName = methodName.replaceFirst("^wave[.]", ""); - } - return OperationType.fromMethodName(methodName); - } - - /** - * Executes an {@link OperationRequest}. If the operation throws an - * {@link InvalidRequestException} this exception will be used to construct an - * error response in the {@link OperationContext}. - * - * @param operation the operation to be executed. If the operation contains - * {@link ParamsProperty.PROXYING_FOR} - then it will be taken in - * account. - * @param operationRegistry the registry containing the operations that can be - * performed. - * @param context the context in which the operation is to be executed. - * @param author the author of the operation. - */ - public static void executeOperation(OperationRequest operation, - OperationServiceRegistry operationRegistry, OperationContext context, ParticipantId author) { - try { - OperationService service = - operationRegistry.getServiceFor(OperationUtil.getOperationType(operation)); - ParticipantId proxyParticipant = OperationUtil.computeParticipant(operation, author); - service.execute(operation, context, proxyParticipant); - } catch (InvalidRequestException e) { - LOG.warning("Operation " + operation + " failed to execute", e); - context.constructErrorResponse(operation, e.getMessage()); - } - } - - /** - * Submits all deltas to the wavelet provider that are generated by the open - * wavelets in the {@link OperationResults}. - * - * @param results the results of performing robot operations. - * @param waveletProvider wavelet provider used to send the deltas to. - * @param requestListener callback for deltas that are submitted to the - * wavelet provider. - */ - public static void submitDeltas(OperationResults results, WaveletProvider waveletProvider, - SubmitRequestListener requestListener) { - for (Entry<WaveletName, RobotWaveletData> entry : results.getOpenWavelets().entrySet()) { - WaveletName waveletName = entry.getKey(); - RobotWaveletData w = entry.getValue(); - for (WaveletDelta delta : w.getDeltas()) { - ProtocolWaveletDelta protocolDelta = CoreWaveletOperationSerializer.serialize(delta); - waveletProvider.submitRequest(waveletName, protocolDelta, requestListener); - } - } - } - - - /** - * Appends proxyFor to the participant address. - * - * @param proxyFor the proxyFor. - * @param participant the participant to apply the proxyFor. - * @return new participant instance in the format - * [email protected]. If proxyFor is null then just - * returns unmodified participant. - * @throws InvalidParticipantAddress if participant address and/or proxy are - * invalid. - */ - public static ParticipantId toProxyParticipant(ParticipantId participant, String proxyFor) - throws InvalidParticipantAddress { - if (!Strings.isNullOrEmpty(proxyFor)) { - RobotName robotName = RobotName.fromAddress(participant.getAddress()); - robotName.setProxyFor(proxyFor); - String robotAddress = robotName.toParticipantAddress(); - if (!RobotName.isWellFormedAddress(robotAddress)) { - throw new InvalidParticipantAddress(robotAddress, - "is not a valid robot name, the proxy is likely to be wrong"); - } - return ParticipantId.of(robotName.toParticipantAddress()); - } else { - return participant; - } - } - - /** - * Computes participant ID using optional {@link ParamsProperty.PROXYING_FOR} - * parameter. - * - * @param operation the operation to be executed. - * @param participant the base participant id. - * @return new participant instance in the format - * [email protected]. If proxyFor is null then just - * returns unmodified participant. - * @throws InvalidRequestException if participant address and/or proxyFor are - * invalid. - */ - public static ParticipantId computeParticipant(OperationRequest operation, - ParticipantId participant) throws InvalidRequestException { - String proxyAddress = - OperationUtil.getOptionalParameter(operation, ParamsProperty.PROXYING_FOR); - try { - return toProxyParticipant(participant, proxyAddress); - } catch (InvalidParticipantAddress e) { - throw new InvalidRequestException( - participant.getAddress() - + (proxyAddress != null ? "+" + proxyAddress : "" - + " is not a valid participant address"), operation); - } - } - - /** - * Builds the supplement model for a wave. - * - * @param operation the operation. - * @param context the operation context. - * @param participant the viewer. - * @return the wave supplement. - * @throws InvalidRequestException if the wave id provided in the operation is - * invalid. - */ - public static SupplementedWave buildSupplement(OperationRequest operation, - OperationContext context, ParticipantId participant) throws InvalidRequestException { - OpBasedWavelet wavelet = context.openWavelet(operation, participant); - ConversationView conversationView = context.getConversationUtil().buildConversation(wavelet); - - // TODO (Yuri Z.) Find a way to obtain an instance of IdGenerator and use it - // to create udwId. - WaveletId udwId = IdUtil.buildUserDataWaveletId(participant); - String waveIdStr = OperationUtil.getRequiredParameter(operation, ParamsProperty.WAVE_ID); - WaveId waveId = null; - try { - waveId = ApiIdSerializer.instance().deserialiseWaveId(waveIdStr); - } catch (InvalidIdException e) { - throw new InvalidRequestException("Invalid WAVE_ID parameter: " + waveIdStr, operation, e); - } - OpBasedWavelet udw = context.openWavelet(waveId, udwId, participant); - - PrimitiveSupplement udwState = WaveletBasedSupplement.create(udw); - - SupplementedWave supplement = - SupplementedWaveImpl.create(udwState, conversationView, participant, DefaultFollow.ALWAYS); - return supplement; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/robots/util/RobotsUtil.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/robots/util/RobotsUtil.java b/src/org/waveprotocol/box/server/robots/util/RobotsUtil.java deleted file mode 100644 index aa61ca9..0000000 --- a/src/org/waveprotocol/box/server/robots/util/RobotsUtil.java +++ /dev/null @@ -1,97 +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.robots.util; - -import com.google.wave.api.Annotation; -import com.google.wave.api.Blip; -import com.google.wave.api.BlipContent; -import com.google.wave.api.Range; - -import org.waveprotocol.box.server.robots.RobotWaveletData; -import org.waveprotocol.box.server.util.WaveletDataUtil; -import org.waveprotocol.wave.model.id.IdURIEncoderDecoder; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.version.HashedVersion; -import org.waveprotocol.wave.model.version.HashedVersionFactory; -import org.waveprotocol.wave.model.version.HashedVersionZeroFactoryImpl; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.data.ObservableWaveletData; -import org.waveprotocol.wave.util.escapers.jvm.JavaUrlCodec; - -/** - * Provides helper methods for the operation services. - * - * @author [email protected] (Yuri Zelikov) - */ -public class RobotsUtil { - - @SuppressWarnings("serial") - public static class RobotRegistrationException extends Exception { - - public RobotRegistrationException (String message) { - super(message); - } - - public RobotRegistrationException(String message, Throwable t) { - super(message, t); - } - } - - private static final IdURIEncoderDecoder URI_CODEC = new IdURIEncoderDecoder(new JavaUrlCodec()); - private static final HashedVersionFactory HASH_FACTORY = new HashedVersionZeroFactoryImpl( - URI_CODEC); - - /** - * Creates a new empty robot wavelet data. - * - * @param participant the wavelet creator. - * @param waveletName the wavelet name. - */ - public static RobotWaveletData createEmptyRobotWavelet(ParticipantId participant, - WaveletName waveletName) { - HashedVersion hashedVersionZero = HASH_FACTORY.createVersionZero(waveletName); - ObservableWaveletData emptyWavelet = - WaveletDataUtil.createEmptyWavelet(waveletName, participant, hashedVersionZero, - System.currentTimeMillis()); - RobotWaveletData newWavelet = new RobotWaveletData(emptyWavelet, hashedVersionZero); - return newWavelet; - } - - /** - * Copies the content of the source blip into the target blip. - * - * @param fromBlip the source blip. - * @param toBlip the target blip. - */ - public static void copyBlipContents(Blip fromBlip, Blip toBlip) { - for (BlipContent blipContent: fromBlip.all().values()) { - toBlip.append(blipContent); - } - for (Annotation annotation : fromBlip.getAnnotations()) { - Range range = annotation.getRange(); - toBlip.range(range.getStart() + 1, range.getEnd() + 1).annotate(annotation.getName(), - annotation.getValue()); - } - } - - private RobotsUtil() { - - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/AbstractSearchServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/AbstractSearchServlet.java b/src/org/waveprotocol/box/server/rpc/AbstractSearchServlet.java deleted file mode 100644 index 7fa14af..0000000 --- a/src/org/waveprotocol/box/server/rpc/AbstractSearchServlet.java +++ /dev/null @@ -1,123 +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.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.ProtocolVersion; -import com.google.wave.api.SearchResult; -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.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.waveserver.WaveletProvider; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.util.logging.Log; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * A base for servlets that provide search functionality. - * - * @author [email protected] (Yuri Z.) - */ -@SuppressWarnings("serial") -public abstract class AbstractSearchServlet extends HttpServlet { - - private static final Log LOG = Log.get(AbstractSearchServlet.class); - - private static String DEFAULT_QUERY = ""; - private static String DEFAULT_NUMRESULTS = "100"; - - protected final ConversationUtil conversationUtil; - protected final EventDataConverterManager converterManager; - protected final WaveletProvider waveletProvider; - protected final SessionManager sessionManager; - protected final OperationServiceRegistry operationRegistry; - - - private static String getParameter(HttpServletRequest req, String paramName, String defaultValue) { - String param = req.getParameter(paramName); - param = param == null ? defaultValue : param; - return param; - } - - /** - * Constructor. - */ - public AbstractSearchServlet(ConversationUtil conversationUtil, - EventDataConverterManager converterManager, WaveletProvider waveletProvider, - SessionManager sessionManager, OperationServiceRegistry operationRegistry) { - this.conversationUtil = conversationUtil; - this.converterManager = converterManager; - this.waveletProvider = waveletProvider; - this.sessionManager = sessionManager; - this.operationRegistry = operationRegistry; - } - - /** - * Extracts search query params from request. - * - * @param req the request. - * @param response the response. - * @return the SearchRequest with query data. - */ - public static SearchRequest parseSearchRequest(HttpServletRequest req, - HttpServletResponse response) { - - String query = getParameter(req, "query", DEFAULT_QUERY); - String index = getParameter(req, "index", "0"); - String numResults = getParameter(req, "numResults", DEFAULT_NUMRESULTS); - SearchRequest searchRequest = - SearchRequest.newBuilder().setQuery(query).setIndex(Integer.parseInt(index)) - .setNumResults(Integer.parseInt(numResults)).build(); - return searchRequest; - } - - /** - * Performs search using Data API. - */ - protected SearchResult performSearch(SearchRequest searchRequest, ParticipantId user) { - OperationQueue opQueue = new OperationQueue(); - opQueue.search(searchRequest.getQuery(), searchRequest.getIndex(), - searchRequest.getNumResults()); - OperationContextImpl context = - new OperationContextImpl(waveletProvider, - converterManager.getEventDataConverter(ProtocolVersion.DEFAULT), conversationUtil); - LOG.fine( - "Performing query: " + searchRequest.getQuery() + " [" + searchRequest.getIndex() + ", " - + (searchRequest.getIndex() + searchRequest.getNumResults()) + "]"); - OperationRequest operationRequest = opQueue.getPendingOperations().get(0); - String opId = operationRequest.getId(); - OperationUtil.executeOperation(operationRequest, operationRegistry, context, user); - JsonRpcResponse jsonRpcResponse = context.getResponses().get(opId); - SearchResult searchResult = - (SearchResult) jsonRpcResponse.getData().get(ParamsProperty.SEARCH_RESULTS); - return searchResult; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/AttachmentInfoServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/AttachmentInfoServlet.java b/src/org/waveprotocol/box/server/rpc/AttachmentInfoServlet.java deleted file mode 100644 index b4dd4a0..0000000 --- a/src/org/waveprotocol/box/server/rpc/AttachmentInfoServlet.java +++ /dev/null @@ -1,143 +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.inject.Inject; -import com.google.inject.Singleton; - -import java.util.logging.Level; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.rpc.ProtoSerializer.SerializationException; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.wave.model.id.InvalidIdException; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.util.logging.Log; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.waveprotocol.box.attachment.AttachmentMetadata; -import org.waveprotocol.box.attachment.AttachmentProto.AttachmentsResponse; -import org.waveprotocol.box.attachment.proto.AttachmentMetadataProtoImpl; -import org.waveprotocol.box.server.attachment.AttachmentService; -import org.waveprotocol.box.server.persistence.AttachmentUtil; -import org.waveprotocol.box.server.waveserver.WaveServerException; -import org.waveprotocol.wave.media.model.AttachmentId; - -/* - * Serves attachments info from a provided store. - * - * @author [email protected] (A. Kaplanov) - */ - -@SuppressWarnings("serial") -@Singleton -public class AttachmentInfoServlet extends HttpServlet { - public static final String ATTACHMENTS_INFO_URL = "/attachmentsInfo"; - - private static final Log LOG = Log.get(AttachmentInfoServlet.class); - - private final AttachmentService service; - private final WaveletProvider waveletProvider; - private final SessionManager sessionManager; - private final ProtoSerializer serializer; - - @Inject - private AttachmentInfoServlet(AttachmentService service, WaveletProvider waveletProvider, - SessionManager sessionManager, ProtoSerializer serializer) { - this.service = service; - this.waveletProvider = waveletProvider; - this.sessionManager = sessionManager; - this.serializer = serializer; - } - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - List<AttachmentId> attachmentIds = getIdsFromRequest(request); - - if (attachmentIds == null) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - - ParticipantId user = sessionManager.getLoggedInUser(request.getSession(false)); - - AttachmentsResponse.Builder attachmentsResponse = AttachmentsResponse.newBuilder(); - for (AttachmentId id : attachmentIds) { - AttachmentMetadata metadata = service.getMetadata(id); - if (metadata != null) { - boolean isAuthorized = false; - WaveletName waveletName = AttachmentUtil.waveRef2WaveletName(metadata.getWaveRef()); - try { - isAuthorized = waveletProvider.checkAccessPermission(waveletName, user); - } catch (WaveServerException e) { - LOG.warning("Problem while authorizing user: " + user + " for wavelet: " + waveletName, e); - } - if (isAuthorized) { - attachmentsResponse.addAttachment(new AttachmentMetadataProtoImpl(metadata).getPB()); - } - } - } - - String info; - try { - info = serializer.toJson(attachmentsResponse.build()).toString(); - } catch (SerializationException ex) { - LOG.log(Level.SEVERE, "Attachments info serialize", ex); - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return; - } - - response.setStatus(HttpServletResponse.SC_OK); - response.setContentType("application/json; charset=utf8"); - response.setHeader("Cache-Control", "no-store"); - response.getWriter().append(info); - - LOG.info("Fetched info for " + attachmentIds.size() + " attachments"); - } - - /** - * Get the attachment Ids from the URL in the request. - * - * @param request - * @return the list of Ids. - */ - private static List<AttachmentId> getIdsFromRequest(HttpServletRequest request) { - String par = request.getParameter("attachmentIds"); - if (par != null) { - List<AttachmentId> ids = new ArrayList<AttachmentId>(); - for (String id : par.split(",", -1)) { - try { - ids.add(AttachmentId.deserialise(id)); - } catch (InvalidIdException ex) { - LOG.log(Level.SEVERE, "Deserialize attachment Id " + id, ex); - } - } - return ids; - } - return null; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/AttachmentServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/AttachmentServlet.java b/src/org/waveprotocol/box/server/rpc/AttachmentServlet.java deleted file mode 100644 index e0d99bf..0000000 --- a/src/org/waveprotocol/box/server/rpc/AttachmentServlet.java +++ /dev/null @@ -1,296 +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.inject.Inject; -import com.google.inject.Singleton; -import com.typesafe.config.Config; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileItemFactory; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.apache.commons.io.FilenameUtils; -import org.waveprotocol.box.attachment.AttachmentMetadata; -import org.waveprotocol.box.server.attachment.AttachmentService; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.persistence.AttachmentStore.AttachmentData; -import org.waveprotocol.box.server.persistence.AttachmentUtil; -import org.waveprotocol.box.server.waveserver.WaveServerException; -import org.waveprotocol.box.server.waveserver.WaveletProvider; -import org.waveprotocol.wave.media.model.AttachmentId; -import org.waveprotocol.wave.model.id.InvalidIdException; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.util.logging.Log; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.*; -import java.net.URLDecoder; -import java.util.Calendar; -import java.util.List; -import java.util.logging.Level; - -/** - * Serves attachments from a provided store. - * - * @author [email protected] (A. Kaplanov) - * - */ - -@SuppressWarnings("serial") -@Singleton -public class AttachmentServlet extends HttpServlet { - public static String ATTACHMENT_URL = "/attachment"; - public static String THUMBNAIL_URL = "/thumbnail"; - - public static String THUMBNAIL_PATTERN_FORMAT_NAME = "png"; - public static String THUMBNAIL_PATTERN_DEFAULT = "default"; - - private static final Log LOG = Log.get(AttachmentServlet.class); - - private final AttachmentService service; - private final WaveletProvider waveletProvider; - private final SessionManager sessionManager; - private final String thumbnailPattternsDirectory; - - @Inject - private AttachmentServlet(AttachmentService service, WaveletProvider waveletProvider, - SessionManager sessionManager, Config config) { - this.service = service; - this.waveletProvider = waveletProvider; - this.sessionManager = sessionManager; - this.thumbnailPattternsDirectory = config.getString("core.thumbnail_patterns_directory"); - } - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - AttachmentId attachmentId = getAttachmentIdFromRequest(request); - - if (attachmentId == null) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - - String fileName = getFileNameFromRequest(request); - String waveRefStr = getWaveRefFromRequest(request); - - AttachmentMetadata metadata = service.getMetadata(attachmentId); - WaveletName waveletName; - - if (metadata == null) { - // Old attachments does not have metainfo. - if (waveRefStr != null) { - waveletName = AttachmentUtil.waveRef2WaveletName(waveRefStr); - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - } else { - waveletName = AttachmentUtil.waveRef2WaveletName(metadata.getWaveRef()); - } - - ParticipantId user = sessionManager.getLoggedInUser(request.getSession(false)); - boolean isAuthorized = false; - try { - isAuthorized = waveletProvider.checkAccessPermission(waveletName, user); - } catch (WaveServerException e) { - LOG.warning("Problem while authorizing user: " + user + " for wavelet: " + waveletName, e); - } - if (!isAuthorized) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - if (metadata == null) { - metadata = service.buildAndStoreMetadataWithThumbnail(attachmentId, waveletName, fileName, null); - } - - String contentType; - AttachmentData data; - if (request.getRequestURI().startsWith(ATTACHMENT_URL)) { - contentType = metadata.getMimeType(); - data = service.getAttachment(attachmentId); - if (data == null) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - } else if (request.getRequestURI().startsWith(THUMBNAIL_URL)) { - if (metadata.hasImageMetadata()) { - contentType = AttachmentService.THUMBNAIL_MIME_TYPE; - data = service.getThumbnail(attachmentId); - if (data == null) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - } else { - contentType = THUMBNAIL_PATTERN_FORMAT_NAME; - data = getThumbnailByContentType(metadata.getMimeType()); - } - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - if (data == null) { - response.sendError(HttpServletResponse.SC_NOT_FOUND); - return; - } - - response.setContentType(contentType); - response.setContentLength((int)data.getSize()); - response.setHeader("Content-Disposition", "attachment; filename=\"" + metadata.getFileName() + "\""); - response.setStatus(HttpServletResponse.SC_OK); - response.setDateHeader("Last-Modified", Calendar.getInstance().getTimeInMillis()); - AttachmentUtil.writeTo(data.getInputStream(), response.getOutputStream()); - - LOG.info("Fetched attachment with id '" + attachmentId + "'"); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, - IOException { - // Process only multipart requests. - if (ServletFileUpload.isMultipartContent(request)) { - // Create a factory for disk-based file items. - FileItemFactory factory = new DiskFileItemFactory(); - - // Create a new file upload handler. - ServletFileUpload upload = new ServletFileUpload(factory); - - // Parse the request. - try { - @SuppressWarnings("unchecked") - List<FileItem> items = upload.parseRequest(request); - AttachmentId id = null; - String waveRefStr = null; - FileItem fileItem = null; - for (FileItem item : items) { - // Process only file upload - discard other form item types. - if (item.isFormField()) { - if (item.getFieldName().equals("attachmentId")) { - id = AttachmentId.deserialise(item.getString()); - } - if (item.getFieldName().equals("waveRef")) { - waveRefStr = item.getString(); - } - } else { - fileItem = item; - } - } - - if (id == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No attachment Id in the request."); - return; - } - if (waveRefStr == null) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No wave reference in request."); - return; - } - - WaveletName waveletName = AttachmentUtil.waveRef2WaveletName(waveRefStr); - ParticipantId user = sessionManager.getLoggedInUser(request.getSession(false)); - boolean isAuthorized = waveletProvider.checkAccessPermission(waveletName, user); - if (!isAuthorized) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - // Get only the file name not whole path. - if (fileItem != null && fileItem.getName() != null) { - String fileName = FilenameUtils.getName(fileItem.getName()); - service.storeAttachment(id, fileItem.getInputStream(), waveletName, fileName, user); - response.setStatus(HttpServletResponse.SC_CREATED); - String msg = - String.format("The file with name: %s and id: %s was created successfully.", - fileName, id); - LOG.fine(msg); - response.getWriter().print("OK"); - response.flushBuffer(); - } - } catch (Exception e) { - LOG.severe("Upload error", e); - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "An error occurred while upload the file : " + e.getMessage()); - } - } else { - LOG.severe("Request contents type is not supported by the servlet."); - response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, - "Request contents type is not supported by the servlet."); - } - } - - private static AttachmentId getAttachmentIdFromRequest(HttpServletRequest request) { - if (request.getPathInfo().length() == 0) { - return null; - } - String id = getAttachmentIdStringFromRequest(request); - try { - return AttachmentId.deserialise(id); - } catch (InvalidIdException ex) { - LOG.log(Level.SEVERE, "Deserialize attachment Id " + id, ex); - return null; - } - } - - private static String getAttachmentIdStringFromRequest(HttpServletRequest request) { - // Discard the leading '/' in the pathinfo. - return request.getPathInfo().substring(1); - } - - private AttachmentData getThumbnailByContentType(String contentType) throws IOException { - File file = new File(thumbnailPattternsDirectory, contentType.replaceAll("/", "_")); - if (!file.exists()) { - file = new File(thumbnailPattternsDirectory, THUMBNAIL_PATTERN_DEFAULT); - } - final File thumbFile = file; - return new AttachmentData() { - - @Override - public InputStream getInputStream() throws IOException { - return new FileInputStream(thumbFile); - } - - @Override - public long getSize() { - return thumbFile.length(); - } - }; - } - - private static String getFileNameFromRequest(HttpServletRequest request) { - String fileName = request.getParameter("fileName"); - return fileName != null ? fileName : ""; - } - - private static String getWaveRefFromRequest(HttpServletRequest request) { - String waveRefStrEncoded = request.getParameter("waveRef"); - String waveRefStr = null; - if (waveRefStrEncoded != null) { - try { - waveRefStr = URLDecoder.decode(waveRefStrEncoded, "UTF-8"); - } catch (UnsupportedEncodingException e) { - LOG.warning("Problem decoding: " + waveRefStrEncoded, e); - } - } - return waveRefStr; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/AuthenticationServlet.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/AuthenticationServlet.java b/src/org/waveprotocol/box/server/rpc/AuthenticationServlet.java deleted file mode 100644 index b282576..0000000 --- a/src/org/waveprotocol/box/server/rpc/AuthenticationServlet.java +++ /dev/null @@ -1,412 +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.Preconditions; -import com.google.common.base.Strings; -import com.google.gxp.base.GxpContext; -import com.google.inject.Inject; -import com.google.inject.name.Named; -import com.typesafe.config.Config; -import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.UrlEncoded; -import org.waveprotocol.box.server.CoreSettingsNames; -import org.waveprotocol.box.server.authentication.HttpRequestBasedCallbackHandler; -import org.waveprotocol.box.server.authentication.ParticipantPrincipal; -import org.waveprotocol.box.server.authentication.SessionManager; -import org.waveprotocol.box.server.gxp.AuthenticationPage; -import org.waveprotocol.box.server.persistence.AccountStore; -import org.waveprotocol.box.server.robots.agent.welcome.WelcomeRobot; -import org.waveprotocol.box.server.util.RegistrationUtil; -import org.waveprotocol.wave.model.id.WaveIdentifiers; -import org.waveprotocol.wave.model.wave.InvalidParticipantAddress; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.util.logging.Log; - -import javax.inject.Singleton; -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; -import javax.naming.ldap.Rdn; -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLDecoder; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CodingErrorAction; -import java.security.Principal; -import java.security.cert.X509Certificate; - -/** - * A servlet for authenticating a user's password and giving them a token via a - * cookie. - * - * @author [email protected] (Joseph Gentle) - */ -@SuppressWarnings("serial") -@Singleton -public class AuthenticationServlet extends HttpServlet { - private static final String DEFAULT_REDIRECT_URL = "/"; - public static final String RESPONSE_STATUS_NONE = "NONE"; - public static final String RESPONSE_STATUS_FAILED = "FAILED"; - public static final String RESPONSE_STATUS_SUCCESS = "SUCCESS"; - // The Object ID of the PKCS #9 email address stored in the client certificate. - // Source: http://www.rsa.com/products/bsafe/documentation/sslc251html/group__AD__COMMON__OIDS.html - private static final String OID_EMAIL = "1.2.840.113549.1.9.1"; - - private static final Log LOG = Log.get(AuthenticationServlet.class); - - private final AccountStore accountStore; - private final Configuration configuration; - private final SessionManager sessionManager; - private final String domain; - private final boolean isClientAuthEnabled; - private final String clientAuthCertDomain; - private final boolean isRegistrationDisabled; - private final boolean isLoginPageDisabled; - private boolean failedClientAuth = false; -private final WelcomeRobot welcomeBot; - private final String analyticsAccount; - - @Inject - public AuthenticationServlet(AccountStore accountStore, - Configuration configuration, - SessionManager sessionManager, - @Named(CoreSettingsNames.WAVE_SERVER_DOMAIN) String domain, - Config config, - WelcomeRobot welcomeBot) { - Preconditions.checkNotNull(accountStore, "AccountStore is null"); - Preconditions.checkNotNull(configuration, "Configuration is null"); - Preconditions.checkNotNull(sessionManager, "Session manager is null"); - - this.accountStore = accountStore; - this.configuration = configuration; - this.sessionManager = sessionManager; - this.domain = domain.toLowerCase(); - this.isClientAuthEnabled = config.getBoolean("security.enable_clientauth"); - this.clientAuthCertDomain = config.getString("security.clientauth_cert_domain").toLowerCase(); - this.isRegistrationDisabled = config.getBoolean("administration.disable_registration"); - this.isLoginPageDisabled = config.getBoolean("administration.disable_loginpage"); - this.welcomeBot = welcomeBot; - this.analyticsAccount = config.getString("administration.analytics_account"); - } - - @SuppressWarnings("unchecked") - private LoginContext login(BufferedReader body) throws IOException, LoginException { - try { - Subject subject = new Subject(); - - String parametersLine = body.readLine(); - // Throws UnsupportedEncodingException. - byte[] utf8Bytes = parametersLine.getBytes("UTF-8"); - - CharsetDecoder utf8Decoder = Charset.forName("UTF-8").newDecoder(); - utf8Decoder.onMalformedInput(CodingErrorAction.IGNORE); - utf8Decoder.onUnmappableCharacter(CodingErrorAction.IGNORE); - - // Throws CharacterCodingException. - CharBuffer parsed = utf8Decoder.decode(ByteBuffer.wrap(utf8Bytes)); - parametersLine = parsed.toString(); - - MultiMap<String> parameters = new UrlEncoded(parametersLine); - CallbackHandler callbackHandler = new HttpRequestBasedCallbackHandler(parameters); - - LoginContext context = new LoginContext("Wave", subject, callbackHandler, configuration); - - // If authentication fails, login() will throw a LoginException. - context.login(); - return context; - } catch (CharacterCodingException cce) { - throw new LoginException("Character coding exception (not utf-8): " - + cce.getLocalizedMessage()); - } catch (UnsupportedEncodingException uee) { - throw new LoginException("ad character encoding specification: " + uee.getLocalizedMessage()); - } - } - - /** - * The POST request should have all the fields required for authentication. - */ - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { - req.setCharacterEncoding("UTF-8"); - LoginContext context; - Subject subject; - ParticipantId loggedInAddress = null; - - if (isClientAuthEnabled) { - boolean skipClientAuth = false; - try { - X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate"); - - if (certs == null) { - if (isLoginPageDisabled) { - throw new IllegalStateException( - "No client X.509 certificate provided (you need to get a certificate" - + "from your systems manager and import it into your browser)."); - } - else { - failedClientAuth = true; - skipClientAuth = true; - doGet(req, resp); - } - } - - if (!skipClientAuth) { - failedClientAuth = false; - subject = new Subject(); - for (X509Certificate cert : certs) { - X500Principal principal = cert.getSubjectX500Principal(); - subject.getPrincipals().add(principal); - } - loggedInAddress = getLoggedInUser(subject); - } - } catch (InvalidParticipantAddress e1) { - throw new IllegalStateException( - "The user provided valid authentication information, but the username" - + " isn't a valid user address."); - } - } - - if (!isLoginPageDisabled && loggedInAddress == null) { - try { - context = login(req.getReader()); - } catch (LoginException e) { - String message = "The username or password you entered is incorrect."; - String responseType = RESPONSE_STATUS_FAILED; - LOG.info("User authentication failed: " + e.getLocalizedMessage()); - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - resp.setContentType("text/html;charset=utf-8"); - AuthenticationPage.write(resp.getWriter(), new GxpContext(req.getLocale()), domain, message, - responseType, isLoginPageDisabled, analyticsAccount); - return; - } - - subject = context.getSubject(); - - try { - loggedInAddress = getLoggedInUser(subject); - } catch (InvalidParticipantAddress e1) { - throw new IllegalStateException( - "The user provided valid authentication information, but the username" - + " isn't a valid user address."); - } - - if (loggedInAddress == null) { - try { - context.logout(); - } catch (LoginException e) { - // Logout failed. Absorb the error, since we're about to throw an - // illegal state exception anyway. - } - - throw new IllegalStateException( - "The user provided valid authentication information, but we don't " - + "know how to map their identity to a wave user address."); - } - } - - HttpSession session = req.getSession(true); - sessionManager.setLoggedInUser(session, loggedInAddress); - LOG.info("Authenticated user " + loggedInAddress); - - redirectLoggedInUser(req, resp); - } - - /** - * Get the participant id of the given subject. - * - * The subject is searched for compatible principals. When other - * authentication types are added, this method will need to be updated to - * support their principal types. - * - * @throws InvalidParticipantAddress The subject's address is invalid - */ - private ParticipantId getLoggedInUser(Subject subject) throws InvalidParticipantAddress { - String address = null; - - for (Principal p : subject.getPrincipals()) { - // TODO(josephg): When we support other authentication types (LDAP, etc), - // this method will need to read the address portion out of the other principal types. - if (p instanceof ParticipantPrincipal) { - address = ((ParticipantPrincipal) p).getName(); - break; - } else if (p instanceof X500Principal) { - return attemptClientCertificateLogin((X500Principal)p); - } - } - - return address == null ? null : ParticipantId.of(address); - } - - /** - * Attempts to authenticate the user using their client certificate. - * - * Retrieves the email from their certificate, using it as the wave username. - * If the user doesn't exist and registration is enabled, it will automatically create an account - * before continuing. Otherwise it will simply check if the account exists and authenticate based - * on that. - * - * @throws RuntimeException The encoding of the email is unsupported on this system - * @throws InvalidParticipantAddress The email address doesn't correspond to an account - */ - private ParticipantId attemptClientCertificateLogin(X500Principal p) - throws RuntimeException, InvalidParticipantAddress { - String distinguishedName = p.getName(); - try { - LdapName ldapName = new LdapName(distinguishedName); - for (Rdn rdn: ldapName.getRdns()) { - if (rdn.getType().equals(OID_EMAIL)) { - String email = decodeEmailFromCertificate((byte[])rdn.getValue()); - if (email.endsWith("@" + clientAuthCertDomain)) { - // Check we decoded the string correctly. - Preconditions.checkState(WaveIdentifiers.isValidIdentifier(email), - "The decoded email is not a valid wave identifier"); - ParticipantId id = ParticipantId.of(email); - if (!RegistrationUtil.doesAccountExist(accountStore, id)) { - if (!isRegistrationDisabled) { - if (!RegistrationUtil.createAccountIfMissing(accountStore, id, null, welcomeBot)) { - return null; - } - } else { - throw new InvalidNameException( - "User doesn't already exist, and registration disabled by administrator"); - } - } - return id; - } - } - } - } catch (UnsupportedEncodingException ex) { - throw new RuntimeException(ex); - } catch (InvalidNameException ex) { - throw new InvalidParticipantAddress(distinguishedName, - "Certificate does not contain a valid distinguished name"); - } - return null; - } - - /** - * Decodes the user email from the X.509 certificate. - * - * Email address is assumed to be valid in ASCII, and less than 128 characters long - * - * @param encoded Output from rdn.getValue(). 1st byte is the tag, second is the length. - * @return The decoded email in ASCII - * @throws UnsupportedEncodingException The email address wasn't in ASCII - */ - private String decodeEmailFromCertificate(byte[] encoded) throws UnsupportedEncodingException { - // Check for < 130, since first 2 bytes are taken up as stated above. - Preconditions.checkState(encoded.length < 130,"The email address is longer than expected"); - return new String(encoded, 2, encoded.length - 2, "ascii"); - } - - /** - * On GET, present a login form if the user isn't authenticated. - */ - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - // If the user is already logged in, we'll try to redirect them immediately. - resp.setCharacterEncoding("UTF-8"); - req.setCharacterEncoding("UTF-8"); - HttpSession session = req.getSession(false); - ParticipantId user = sessionManager.getLoggedInUser(session); - - if (user != null) { - redirectLoggedInUser(req, resp); - } else { - if (isClientAuthEnabled && !failedClientAuth) { - X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate"); - if (certs != null) { - doPost(req, resp); - } - } - - if (!isLoginPageDisabled) { - resp.setStatus(HttpServletResponse.SC_OK); - } - else { - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - } - resp.setContentType("text/html;charset=utf-8"); - AuthenticationPage.write(resp.getWriter(), new GxpContext(req.getLocale()), domain, "", - RESPONSE_STATUS_NONE, isLoginPageDisabled, analyticsAccount); - } - } - - /** - * Redirect the user back to DEFAULT_REDIRECT_URL, unless a custom redirect - * URL has been specified in the query string; in which case redirect there. - * - * Only redirects to local URLs are allowed. - * - * @throws IOException - */ - private void redirectLoggedInUser(HttpServletRequest req, HttpServletResponse resp) - throws IOException { - Preconditions.checkState(sessionManager.getLoggedInUser(req.getSession(false)) != null, - "The user is not logged in"); - String query = req.getQueryString(); - - // Not using req.getParameter() for this because calling that method might parse the password - // sitting in POST data into a String, where it could be read by another process after the - // string is garbage collected. - if (query == null || !query.startsWith("r=")) { - resp.sendRedirect(DEFAULT_REDIRECT_URL); - return; - } - - String encoded_url = query.substring("r=".length()); - String path = URLDecoder.decode(encoded_url, "UTF-8"); - - // The URL must not be an absolute URL to prevent people using this as a - // generic redirection service. - URI uri; - try { - uri = new URI(path); - } catch (URISyntaxException e) { - // The redirect URL is invalid. - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return; - } - - if (Strings.isNullOrEmpty(uri.getHost()) == false) { - // The URL includes a host component. Disallow it. - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } else { - resp.sendRedirect(path); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/rpc/ClientRpcChannel.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/rpc/ClientRpcChannel.java b/src/org/waveprotocol/box/server/rpc/ClientRpcChannel.java deleted file mode 100644 index 148c58a..0000000 --- a/src/org/waveprotocol/box/server/rpc/ClientRpcChannel.java +++ /dev/null @@ -1,36 +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.RpcChannel; -import com.google.protobuf.RpcController; - -/** - * Provides the client end-point of a wave server connection. Used to generate - * usable Stub implementations of any service type. - */ -public interface ClientRpcChannel extends RpcChannel { - /** - * Return a new RpcController for users of this RpcChannel. - * - * @return the new RpcController implementation - */ - public RpcController newRpcController(); -}
