Author: al
Date: Tue Aug 27 19:21:36 2013
New Revision: 1517940
URL: http://svn.apache.org/r1517940
Log:
Merge branch 'trunk-staging' into 0.4-release-staging
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/ClientFrontendImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/WaveletInfo.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/LocalWaveletContainer.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/MemoryPerUserWaveViewHandlerImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/PerUserWaveViewDistpatcher.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/RemoteWaveletContainerImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/Wave.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveServerImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveletContainerImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/client/WindowTitleHandler.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/search/WaveBasedDigest.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/StageTwo.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/wavepanel/impl/reader/Reader.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/conversation/TitleHelper.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGenerator.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGeneratorImpl.java
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/wave/opbased/WaveViewImpl.java
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImplTest.java
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/wave/concurrencycontrol/wave/CcBasedWaveViewTest.java
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/ClientFrontendImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/ClientFrontendImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/ClientFrontendImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/ClientFrontendImpl.java
Tue Aug 27 19:21:36 2013
@@ -229,6 +229,9 @@ public class ClientFrontendImpl implemen
*/
private void participantUpdate(WaveletName waveletName, ParticipantId
participant,
DeltaSequence newDeltas, boolean add, boolean remove) {
+ if(LOG.isFineLoggable()) {
+ LOG.fine("Notifying " + participant + " for " + waveletName);
+ }
if (add) {
waveletInfo.notifyAddedExplicitWaveletParticipant(waveletName,
participant);
}
@@ -249,6 +252,11 @@ public class ClientFrontendImpl implemen
}
WaveletName waveletName = WaveletName.of(wavelet.getWaveId(),
wavelet.getWaveletId());
+
+ if(waveletInfo.getCurrentWaveletVersion(waveletName).getVersion() == 0 &&
LOG.isWarningLoggable()) {
+ LOG.warning("Wavelet does not appear to have been initialized by client.
Continuing anyway.");
+ }
+
waveletInfo.syncWaveletVersion(waveletName, newDeltas);
Set<ParticipantId> remainingparticipants =
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/WaveletInfo.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/WaveletInfo.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/WaveletInfo.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/frontend/WaveletInfo.java
Tue Aug 27 19:21:36 2013
@@ -35,6 +35,7 @@ import org.waveprotocol.wave.model.versi
import org.waveprotocol.wave.model.version.HashedVersionFactory;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
+import org.waveprotocol.wave.util.logging.Log;
import java.util.Map;
import java.util.Map.Entry;
@@ -48,6 +49,7 @@ import java.util.Set;
* @see ClientFrontendImpl
*/
public class WaveletInfo {
+ private static final Log LOG = Log.get(WaveletInfo.class);
/** Information we hold in memory for each wavelet. */
private static class PerWavelet {
@@ -135,6 +137,10 @@ public class WaveletInfo {
* Initializes front-end information from the wave store, if necessary.
*/
public void initialiseWave(WaveId waveId) throws WaveServerException {
+ if(LOG.isFineLoggable()) {
+ LOG.fine("frontend initialiseWave(" + waveId +")");
+ }
+
if (!perWavelet.containsKey(waveId)) {
Map<WaveletId, PerWavelet> wavelets = perWavelet.get(waveId);
for (WaveletId waveletId : waveletProvider.getWaveletIds(waveId)) {
@@ -144,6 +150,9 @@ public class WaveletInfo {
PerWavelet waveletInfo = wavelets.get(waveletId);
synchronized (waveletInfo) {
waveletInfo.currentVersion = wavelet.getHashedVersion();
+ if(LOG.isFineLoggable()) {
+ LOG.fine("frontend wavelet " + waveletId + " @" +
wavelet.getHashedVersion().getVersion());
+ }
waveletInfo.explicitParticipants.addAll(wavelet.getParticipants());
}
}
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/LocalWaveletContainer.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/LocalWaveletContainer.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/LocalWaveletContainer.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/LocalWaveletContainer.java
Tue Aug 27 19:21:36 2013
@@ -38,7 +38,7 @@ import org.waveprotocol.wave.model.versi
interface LocalWaveletContainer extends WaveletContainer {
/**
- * Manufactures remote wavelet containers.
+ * Manufactures local wavelet containers.
*/
interface Factory extends WaveletContainer.Factory<LocalWaveletContainer> { }
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/MemoryPerUserWaveViewHandlerImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/MemoryPerUserWaveViewHandlerImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/MemoryPerUserWaveViewHandlerImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/MemoryPerUserWaveViewHandlerImpl.java
Tue Aug 27 19:21:36 2013
@@ -97,7 +97,10 @@ public class MemoryPerUserWaveViewHandle
Multimap<WaveId, WaveletId> perUserView =
explicitPerUserWaveViews.get(user);
if (!perUserView.containsEntry(waveletName.waveId,
waveletName.waveletId)) {
perUserView.put(waveletName.waveId, waveletName.waveletId);
- LOG.fine("Added wavelet: " + waveletName + " to the view of user: " +
user.getAddress());
+ if(LOG.isFineLoggable()) {
+ LOG.fine("Added wavelet: " + waveletName + " to the view of user: "
+ user.getAddress());
+ LOG.fine("View size is now: " + perUserView.size());
+ }
}
}
SettableFuture<Void> task = SettableFuture.create();
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/PerUserWaveViewDistpatcher.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/PerUserWaveViewDistpatcher.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/PerUserWaveViewDistpatcher.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/PerUserWaveViewDistpatcher.java
Tue Aug 27 19:21:36 2013
@@ -30,6 +30,7 @@ import org.waveprotocol.wave.model.opera
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
+import org.waveprotocol.wave.util.logging.Log;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -39,6 +40,7 @@ import java.util.concurrent.CopyOnWriteA
* @author [email protected] (Yuri Zelikov)
*/
public class PerUserWaveViewDistpatcher implements WaveBus.Subscriber,
PerUserWaveViewBus {
+ private static final Log LOG = Log.get(PerUserWaveViewDistpatcher.class);
private static final CopyOnWriteArraySet<PerUserWaveViewBus.Listener>
listeners =
new CopyOnWriteArraySet<PerUserWaveViewBus.Listener>();
@@ -48,11 +50,19 @@ public class PerUserWaveViewDistpatcher
WaveletId waveletId = wavelet.getWaveletId();
WaveId waveId = wavelet.getWaveId();
WaveletName waveletName = WaveletName.of(waveId, waveletId);
+ if(LOG.isInfoLoggable()) {
+ LOG.info("Got update for " + waveId + " " + waveletId);
+ }
+
// Find whether participants were added/removed and update the views
// accordingly.
for (TransformedWaveletDelta delta : deltas) {
for (WaveletOperation op : delta) {
if (op instanceof AddParticipant) {
+ if(LOG.isInfoLoggable()) {
+ LOG.info("Update contains AddParticipant for " +
((AddParticipant)op).getParticipantId());
+ }
+
ParticipantId user = ((AddParticipant) op).getParticipantId();
// Check first if we need to update views for this user.
for (Listener listener : listeners) {
@@ -82,4 +92,4 @@ public class PerUserWaveViewDistpatcher
public void removeListener(Listener listener) {
listeners.remove(listener);
}
-}
\ No newline at end of file
+}
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/RemoteWaveletContainerImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/RemoteWaveletContainerImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/RemoteWaveletContainerImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/RemoteWaveletContainerImpl.java
Tue Aug 27 19:21:36 2013
@@ -51,7 +51,9 @@ import org.waveprotocol.wave.model.opera
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.util.logging.Log;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.concurrent.Executor;
@@ -73,6 +75,13 @@ class RemoteWaveletContainerImpl extends
pendingDeltas = Maps.newTreeMap();
/**
+ * Tracks the highest version commit notice received, which can not be
performed
+ * due to not yet having the required deltas. This must only be access under
writeLock.
+ */
+ private boolean pendingCommit = false;
+ private HashedVersion pendingCommitVersion;
+
+ /**
* Create a new RemoteWaveletContainerImpl. Just pass through to the parent
* constructor.
*/
@@ -95,14 +104,50 @@ class RemoteWaveletContainerImpl extends
@Override
public void commit(HashedVersion version) {
+ try {
+ awaitLoad();
+ }
+ catch(WaveletStateException ex) {
+ LOG.warning("Failed to load " + getWaveletName() + " to perform
commit.", ex);
+ acquireWriteLock();
+ markStateCorrupted();
+ releaseWriteLock();
+ return;
+ }
+
acquireWriteLock();
try {
- persist(version, ImmutableSet.<String>of());
+ attemptCommit(version);
} finally {
releaseWriteLock();
}
}
+ /**
+ * Attempts to commit at the given version.
+ * This will only succeed if we are actually up to date.
+ * If not, then the history is assumed to be coming, and so we can just skip
the whole task.
+ * */
+ private void attemptCommit(HashedVersion version) {
+ HashedVersion expectedVersion = getCurrentVersion();
+ if(expectedVersion == null || version.getVersion() ==
expectedVersion.getVersion()) {
+ LOG.info("Committed " + getWaveletName() + " at version " +
version.getVersion());
+ persist(version, ImmutableSet.<String>of());
+ if(pendingCommitVersion == null || (version.getVersion() >=
pendingCommitVersion.getVersion())) {
+ pendingCommit = false;
+ }
+ } else {
+ LOG.info("Ignoring commit request at " + version.getVersion() +
+ " since only at " + expectedVersion.getVersion());
+ if(pendingCommitVersion == null ||
+ (pendingCommitVersion != null && pendingCommitVersion.getVersion() <
version.getVersion())) {
+ pendingCommitVersion = version;
+ }
+ LOG.info("pendingCommitVersion is now " +
pendingCommitVersion.getVersion());
+ pendingCommit = true;
+ }
+ }
+
private void internalUpdate(final List<ByteString> deltas,
final String domain, final WaveletFederationProvider federationProvider,
final CertificateManager certificateManager, final SettableFuture<Void>
futureResult) {
@@ -176,6 +221,18 @@ class RemoteWaveletContainerImpl extends
List<ByteStringMessage<ProtocolAppliedWaveletDelta>> appliedDeltas,
final String domain, final WaveletFederationProvider federationProvider,
final CertificateManager certificateManager, final SettableFuture<Void>
futureResult) {
+
+ try {
+ awaitLoad();
+ }
+ catch(WaveletStateException ex) {
+ LOG.warning("Failed to load " + getWaveletName() + " to perform
update.", ex);
+ acquireWriteLock();
+ markStateCorrupted();
+ releaseWriteLock();
+ return;
+ }
+
LOG.info("Passed signer info check, now applying all " +
appliedDeltas.size() + " deltas");
acquireWriteLock();
try {
@@ -230,6 +287,11 @@ class RemoteWaveletContainerImpl extends
HashedVersion appliedAt = first.getKey();
ByteStringMessage<ProtocolAppliedWaveletDelta> appliedDelta =
first.getValue();
+ if(LOG.isInfoLoggable()) {
+ LOG.info("pendingDeltas.size(): " +
Integer.toString(pendingDeltas.size()));
+ LOG.info("current appliedAt: " + appliedAt.getVersion() + "
expected: " + expectedVersion.getVersion());
+ }
+
// If we don't have the right version it implies there is a history we
need, so set up a
// callback to request it and fall out of this update
if (appliedAt.getVersion() > expectedVersion.getVersion()) {
@@ -310,14 +372,8 @@ class RemoteWaveletContainerImpl extends
pendingDeltas.remove(appliedAt);
}
- if (!haveRequestedHistory) {
- notifyOfDeltas(resultingDeltas.build(), ImmutableSet.<String>of());
- futureResult.set(null);
- } else if (!resultingDeltas.build().isEmpty()) {
- LOG.severe("History requested but non-empty result, non-contiguous
deltas?");
- } else {
- LOG.info("History requested, ignoring callback");
- }
+ commitAndNotifyResultingDeltas(resultingDeltas, futureResult);
+
} catch (WaveServerException e) {
LOG.warning("Update failure", e);
// TODO(soren): make everyone throw FederationException instead
@@ -330,6 +386,30 @@ class RemoteWaveletContainerImpl extends
}
/**
+ * Commits the resulting deltas, notifying the server of them.
+ * Assumes that everything in resultingDeltas is now in-order, since
+ * even if the original stream was non-contiguous, we have requestedHistory.
+ * Even if not, it is still safe to commit up to the fragmented point.
+ */
+ private void commitAndNotifyResultingDeltas(
+ ImmutableList.Builder<WaveletDeltaRecord> resultingDeltas,
+ final SettableFuture<Void> futureResult) {
+ if(!resultingDeltas.build().isEmpty()) {
+ notifyOfDeltas(resultingDeltas.build(), ImmutableSet.<String>of());
+ futureResult.set(null);
+
+ //Attempt to run any pending commit
+ if(pendingCommit) {
+ releaseWriteLock();
+ commit(pendingCommitVersion);
+ acquireWriteLock();
+ }
+ } else {
+ LOG.info("No deltas in list (fetching history?), ignoring callback");
+ }
+ }
+
+ /**
* Apply a serialised applied delta to a remote wavelet. This assumes the
* caller has validated that the delta is at the correct version and can be
* applied to the wavelet. Must be called with writelock held.
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java
Tue Aug 27 19:21:36 2013
@@ -111,6 +111,13 @@ public class SimpleSearchProviderImpl im
Function<ReadableWaveletData, Boolean> filterWaveletsFunction =
createFilterWaveletsFunction(user, isAllQuery, withParticipantIds,
creatorParticipantIds);
Map<WaveId, WaveViewData> results =
filterWavesViewBySearchCriteria(filterWaveletsFunction, currentUserWavesView);
+
+ if(LOG.isFineLoggable()) {
+ for(Map.Entry e : results.entrySet()) {
+ LOG.fine("filtered results contains: " + e.getKey());
+ }
+ }
+
Collection<WaveViewData> searchResult =
computeSearchResult(user, startAt, numResults, queryParams, results);
LOG.info("Search response to '" + query + "': " + searchResult.size() + "
results, user: "
@@ -128,6 +135,13 @@ public class SimpleSearchProviderImpl im
// shared domain participant.
currentUserWavesView.putAll(waveViewProvider.retrievePerUserWaveView(sharedDomainParticipantId));
}
+
+ if(LOG.isFineLoggable()) {
+ for(Map.Entry e : currentUserWavesView.entries()) {
+ LOG.fine("unfiltered view contains: " + e.getKey() + " " +
e.getValue());
+ }
+ }
+
return currentUserWavesView;
}
@@ -167,16 +181,39 @@ public class SimpleSearchProviderImpl im
for (WaveletId waveletId : waveletIds) {
WaveletContainer waveletContainer = null;
WaveletName waveletname = WaveletName.of(waveId, waveletId);
+
+ // TODO (alown): Find some way to use isLocalWavelet to do this
properly!
try {
- waveletContainer = waveMap.getLocalWavelet(waveletname);
+ if(LOG.isFineLoggable()) {
+ LOG.fine("Trying as a remote wavelet");
+ }
+ waveletContainer = waveMap.getRemoteWavelet(waveletname);
} catch (WaveletStateException e) {
- LOG.severe(String.format("Failed to get local wavelet %s",
waveletname.toString()), e);
+ LOG.severe(String.format("Failed to get remote wavelet %s",
waveletname.toString()), e);
+ } catch (NullPointerException e) {
+ // This is a fairly normal case of it being a local-only wave.
+ // Yet this only seems to appear in the test suite.
+ // Continuing is completely harmless here.
+ LOG.info(String.format("%s is definitely not a remote wavelet. (Null
key)", waveletname.toString()), e);
}
+
+ if(waveletContainer == null) {
+ try {
+ if(LOG.isFineLoggable()) {
+ LOG.fine("Trying as a local wavelet");
+ }
+ waveletContainer = waveMap.getLocalWavelet(waveletname);
+ } catch (WaveletStateException e) {
+ LOG.severe(String.format("Failed to get local wavelet %s",
waveletname.toString()), e);
+ }
+ }
+
// TODO (Yuri Z.) This loop collects all the wavelets that match the
// query, so the view is determined by the query. Instead we should
// look at the user's wave view and determine if the view matches the
query.
try {
if (waveletContainer == null ||
!waveletContainer.applyFunction(matchesFunction)) {
+ LOG.fine("----doesn't match: " + waveletContainer);
continue;
}
if (view == null) {
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/Wave.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/Wave.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/Wave.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/Wave.java
Tue Aug 27 19:21:36 2013
@@ -31,6 +31,7 @@ import org.waveprotocol.box.server.persi
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.util.logging.Log;
import java.util.Iterator;
import java.util.concurrent.ConcurrentMap;
@@ -41,6 +42,8 @@ import java.util.concurrent.ConcurrentMa
* @author [email protected] (Soren Lassen)
*/
final class Wave implements Iterable<WaveletContainer> {
+ private static final Log LOG = Log.get(Wave.class);
+
private class WaveletCreator<T extends WaveletContainer> implements
Function<WaveletId, T> {
private final WaveletContainer.Factory<T> factory;
@@ -120,6 +123,18 @@ final class Wave implements Iterable<Wav
throw new WaveletStateException(
"Interrupted looking up wavelet " + WaveletName.of(waveId,
waveletId), e);
}
+
+ if(LOG.isFineLoggable()) {
+ if(storedWavelets != null) {
+ if(storedWavelets.contains(waveletId)) {
+ LOG.fine("Wavelet is in storedWavelets");
+ }
+ if(waveletsMap.containsKey(waveletId)) {
+ LOG.fine("Wavelet is in wavletsMap");
+ }
+ }
+ }
+
// Since waveletsMap is a computing map, we must call
containsKey(waveletId)
// to tell if waveletId is mapped, we cannot test if get(waveletId)
returns null.
if (storedWavelets != null && !storedWavelets.contains(waveletId)
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveServerImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveServerImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveServerImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveServerImpl.java
Tue Aug 27 19:21:36 2013
@@ -138,7 +138,7 @@ public class WaveServerImpl implements W
if (isLocalWavelet(waveletName)) {
LOG.warning("Got commit update for local wavelet " + waveletName);
- callback.onFailure(FederationErrors.badRequest("Received comit
update to local wavelet"));
+ callback.onFailure(FederationErrors.badRequest("Received commit
update to local wavelet"));
return;
}
@@ -153,17 +153,29 @@ public class WaveServerImpl implements W
if (wavelet != null) {
wavelet.commit(CoreWaveletOperationSerializer.deserialize(committedVersion));
} else {
- // TODO(soren): This should really be changed to create the wavelet
if it doesn't
- // already exist and go get history up committedVersion. Moreover,
when the
- // protocol is enhanced to deliver commit updates reliably, we will
probably need
- // to only return success when we successfully retrieved history and
persisted it all.
- LOG.info("Got commit update for missing wavelet " + waveletName);
+ if(LOG.isInfoLoggable()) {
+ LOG.info("Got commit update for missing wavelet " + waveletName);
+ }
+ createAndCommitRemoteWavelet(waveletName, committedVersion);
}
callback.onSuccess();
}
};
}
+ /**
+ * Creates the non-existent remote wavelet container at this server and
commits it.
+ * Calling commit at this known version, forces the history to be fetched up
to this point.
+ * TODO (alown): Possible race condition here with update? (Though I don't
think it would result in
+ * anything more serious than repeated history fetches.)
+ */
+ private void createAndCommitRemoteWavelet(WaveletName waveletName,
ProtocolHashedVersion committedVersion) {
+ RemoteWaveletContainer wavelet = getOrCreateRemoteWavelet(waveletName);
+ HashedVersion v =
CoreWaveletOperationSerializer.deserialize(committedVersion);
+ wavelet.commit(v);
+ LOG.info("Passed commit message for version " + v.getVersion() + " to
RemoteWavelet");
+ }
+
//
// WaveletFederationProvider implementation.
//
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveletContainerImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveletContainerImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveletContainerImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/server/waveserver/WaveletContainerImpl.java
Tue Aug 27 19:21:36 2013
@@ -57,6 +57,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.Nullable;
+
/**
* Contains the history of a wavelet - applied and transformed deltas plus the
* content of the wavelet.
@@ -484,7 +486,7 @@ abstract class WaveletContainerImpl impl
@Override
public void requestHistory(HashedVersion startVersion, HashedVersion
endVersion,
- Receiver<ByteStringMessage<ProtocolAppliedWaveletDelta>> receiver)
+ Receiver<ByteStringMessage<ProtocolAppliedWaveletDelta>> receiver)
throws AccessControlException, WaveletStateException {
acquireReadLock();
try {
@@ -548,7 +550,11 @@ abstract class WaveletContainerImpl impl
}
}
+ @Nullable
protected HashedVersion getCurrentVersion() {
+ if(waveletState == null)
+ return null;
+
return waveletState.getCurrentVersion();
}
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/client/WindowTitleHandler.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/client/WindowTitleHandler.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/client/WindowTitleHandler.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/client/WindowTitleHandler.java
Tue Aug 27 19:21:36 2013
@@ -57,10 +57,8 @@ public final class WindowTitleHandler im
@Override
public void onOpened(WaveContext wave) {
- Document document =
-
wave.getConversations().getRoot().getRootThread().getFirstBlip().getContent();
- String waveTitle = TitleHelper.extractTitle(document);
- String windowTitle = formatTitle(waveTitle);
+ String waveTitle = TitleHelper.getTitle(wave);
+ String windowTitle = formatTitle(waveTitle);
if (waveTitle == null || waveTitle.isEmpty()) {
windowTitle = DEFAULT_TITLE;
}
@@ -76,4 +74,4 @@ public final class WindowTitleHandler im
private String formatTitle(String title) {
return title + " - " + Session.get().getAddress() + " - " + APP_NAME;
}
-}
\ No newline at end of file
+}
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/search/WaveBasedDigest.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/search/WaveBasedDigest.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/search/WaveBasedDigest.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/box/webclient/search/WaveBasedDigest.java
Tue Aug 27 19:21:36 2013
@@ -179,8 +179,7 @@ public final class WaveBasedDigest
@Override
public String getTitle() {
- return TitleHelper.extractTitle(
-
wave.getConversations().getRoot().getRootThread().getFirstBlip().getContent());
+ return TitleHelper.getTitle(wave);
}
@Override
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/StageTwo.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/StageTwo.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/StageTwo.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/StageTwo.java
Tue Aug 27 19:21:36 2013
@@ -463,7 +463,7 @@ public interface StageTwo {
}
};
WaveViewImpl<OpBasedWavelet> wave =
- WaveViewImpl.create(waveletFactory, getWaveData().getWaveId(),
getIdGenerator(),
+ WaveViewImpl.create(waveletFactory, snapshot.getWaveId(),
getIdGenerator(),
getSignedInUser(), WaveletConfigurator.ADD_CREATOR);
// Populate the initial state.
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/wavepanel/impl/reader/Reader.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/wavepanel/impl/reader/Reader.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/wavepanel/impl/reader/Reader.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/client/wavepanel/impl/reader/Reader.java
Tue Aug 27 19:21:36 2013
@@ -90,7 +90,10 @@ public final class Reader implements Foc
}
public boolean isRead(BlipView blipUi) {
- return !supplement.isUnread(models.getBlip(blipUi));
+ ConversationBlip blip = models.getBlip(blipUi);
+ if(blip != null)
+ return !supplement.isUnread(blip);
+ return false;
}
//
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/conversation/TitleHelper.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/conversation/TitleHelper.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/conversation/TitleHelper.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/conversation/TitleHelper.java
Tue Aug 27 19:21:36 2013
@@ -19,7 +19,9 @@
package org.waveprotocol.wave.model.conversation;
-
+//TODO (alown): should the WaveContext live under model instead?
+import org.waveprotocol.box.webclient.search.WaveContext;
+import org.waveprotocol.wave.model.document.Document;
import org.waveprotocol.wave.model.document.MutableDocument;
import org.waveprotocol.wave.model.document.ReadableWDocument;
import org.waveprotocol.wave.model.document.operation.Attributes;
@@ -239,6 +241,50 @@ public final class TitleHelper {
}
}
+ /**
+ * An error-absorbing title retrieving convenience function.
+ * Please use this rather than doing:
+ *
wave.getConversations().getRoot().getRootThread().getFirstBlip().getContent()
+ * as that is the cause of _many_ shiny's in the client.
+ * In the event something went wrong, or no title exists will return the
empty string.
+ * This is deliberate, so that it doesn't propagate an error for a rather
non-critical
+ * code path.
+ */
+ public static String getTitle(WaveContext waveCtx) {
+ ObservableConversationView conversations = waveCtx.getConversations();
+ if(conversations == null) {
+ return "";
+ }
+
+ ObservableConversation rootConversation = conversations.getRoot();
+ if(rootConversation == null) {
+ return "";
+ }
+
+ ObservableConversationThread rootThread = rootConversation.getRootThread();
+ if(rootThread == null) {
+ return "";
+ }
+
+ ObservableConversationBlip firstBlip = rootThread.getFirstBlip();
+ if(firstBlip == null) {
+ return "";
+ }
+
+ Document doc = firstBlip.getContent();
+ if(doc == null) {
+ return "";
+ }
+
+ String title = extractTitle(doc);
+ if(title == null) {
+ return "";
+ }
+
+ return title;
+ }
+
private TitleHelper() {
}
}
+
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGenerator.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGenerator.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGenerator.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGenerator.java
Tue Aug 27 19:21:36 2013
@@ -61,6 +61,13 @@ public interface IdGenerator {
WaveletId newConversationRootWaveletId();
/**
+ * Creates/gets a root wavelet id for the given waveId
+ * (Federation happy version of newConversationRootWaveletId)
+ */
+
+ WaveletId buildConversationRootWaveletId(WaveId waveId);
+
+ /**
* Creates a user data wavelet id.
*
* Per-user data wavelets are specified by a leading token "user" followed by
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGeneratorImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGeneratorImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGeneratorImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/id/IdGeneratorImpl.java
Tue Aug 27 19:21:36 2013
@@ -75,6 +75,7 @@ public class IdGeneratorImpl implements
return build(IdConstants.BLIP_PREFIX, peekUniqueToken());
}
+ //NOTE: These are _NOT_ federation happy. Ensure that your caller is!
@Override
public WaveId newWaveId() {
return WaveId.of(defaultDomain, newId(WAVE_PREFIX));
@@ -91,6 +92,11 @@ public class IdGeneratorImpl implements
}
@Override
+ public WaveletId buildConversationRootWaveletId(WaveId waveId) {
+ return WaveletId.of(waveId.getDomain(), CONVERSATION_ROOT_WAVELET);
+ }
+
+ @Override
public WaveletId newUserDataWaveletId(String address) {
// TODO(anorth): Take ParticipantId as a parameter after moving it
// into model.id package.
Modified:
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/wave/opbased/WaveViewImpl.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/wave/opbased/WaveViewImpl.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/wave/opbased/WaveViewImpl.java
(original)
+++
incubator/wave/branches/wave-0.4-release/src/org/waveprotocol/wave/model/wave/opbased/WaveViewImpl.java
Tue Aug 27 19:21:36 2013
@@ -131,7 +131,7 @@ public final class WaveViewImpl<T extend
this.viewer = viewer;
this.idGenerator = idGenerator;
this.configurator = configurator;
- this.rootId = idGenerator.newConversationRootWaveletId();
+ this.rootId = idGenerator.buildConversationRootWaveletId(waveId);
this.userDataId = idGenerator.newUserDataWaveletId(viewer.getAddress());
}
Modified:
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImplTest.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImplTest.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImplTest.java
(original)
+++
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImplTest.java
Tue Aug 27 19:21:36 2013
@@ -207,7 +207,7 @@ public class SimpleSearchProviderImplTes
waveMap =
new WaveMap(waveletStore, notifiee, notifiee,
localWaveletContainerFactory,
- remoteWaveletContainerFactory, "example.com", lookupExecutor);
+ remoteWaveletContainerFactory, DOMAIN, lookupExecutor);
searchProvider = new SimpleSearchProviderImpl(DOMAIN, digester, waveMap,
waveViewProvider);
}
Modified:
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/wave/concurrencycontrol/wave/CcBasedWaveViewTest.java
URL:
http://svn.apache.org/viewvc/incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/wave/concurrencycontrol/wave/CcBasedWaveViewTest.java?rev=1517940&r1=1517939&r2=1517940&view=diff
==============================================================================
---
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/wave/concurrencycontrol/wave/CcBasedWaveViewTest.java
(original)
+++
incubator/wave/branches/wave-0.4-release/test/org/waveprotocol/wave/concurrencycontrol/wave/CcBasedWaveViewTest.java
Tue Aug 27 19:21:36 2013
@@ -65,7 +65,7 @@ public class CcBasedWaveViewTest extends
private static final WaveId WAVE_ID = WaveId.of("example.com", "waveId_1");
private static final WaveletId GENERATED_WAVELET_ID =
WaveletId.of("example.com", "some_id");
private static final WaveletId ROOT_WAVELET_ID
- = new IdGeneratorImpl("example.com",
null).newConversationRootWaveletId();
+ = new IdGeneratorImpl("example.com",
null).buildConversationRootWaveletId(WAVE_ID);
private static final String GENERATED_BLIP_ID = "some blip id";
private static final ParticipantId USER_ID = new
ParticipantId("[email protected]");
private static final SchemaProvider SCHEMAS = SchemaCollection.empty();
@@ -214,6 +214,11 @@ public class CcBasedWaveViewTest extends
}
@Override
+ public WaveletId buildConversationRootWaveletId(WaveId waveId) {
+ return ROOT_WAVELET_ID;
+ }
+
+ @Override
public String newDataDocumentId() {
throw new UnsupportedOperationException("Unsupported for test");
}