private ParticipantId computeCreator(WaveViewData wave) { for (ObservableWaveletData wavelet : wave.getWavelets()) { if (IdUtil.isConversationRootWaveletId(wavelet.getWaveletId())) { return wavelet.getCreator(); } } // If not found creator - compare with UNKNOWN_CREATOR; return UNKNOWN_CREATOR; }
private long computeCreatedTime(WaveViewData wave) { long creationTime = -1; for (ObservableWaveletData wavelet : wave.getWavelets()) { creationTime = creationTime < wavelet.getCreationTime() ? wavelet.getCreationTime() : creationTime; } return creationTime; }
private long computeLmt(WaveViewData wave) { long lmt = -1; for (ObservableWaveletData wavelet : wave.getWavelets()) { // Skip non conversational wavelets. if (!IdUtil.isConversationalId(wavelet.getWaveletId())) { continue; } lmt = lmt < wavelet.getLastModifiedTime() ? wavelet.getLastModifiedTime() : lmt; } return lmt; }
protected WaveViewImpl<OpBasedWavelet> createWave() { WaveViewData snapshot = getWaveData(); // The operationalizer makes the wavelets function via operation control. // The hookup with concurrency-control and remote operation streams occurs // later in createUpgrader(). final WaveletOperationalizer operationalizer = getWavelets(); WaveletFactory<OpBasedWavelet> waveletFactory = new WaveletFactory<OpBasedWavelet>() { @Override public OpBasedWavelet create(WaveId waveId, WaveletId id, ParticipantId creator) { long now = System.currentTimeMillis(); ObservableWaveletData data = new WaveletDataImpl( id, creator, now, 0L, HashedVersion.unsigned(0), now, waveId, getDocumentRegistry()); return operationalizer.operationalize(data); } }; WaveViewImpl<OpBasedWavelet> wave = WaveViewImpl.create( waveletFactory, snapshot.getWaveId(), getIdGenerator(), getSignedInUser(), WaveletConfigurator.ADD_CREATOR); // Populate the initial state. for (ObservableWaveletData waveletData : snapshot.getWavelets()) { wave.addWavelet(operationalizer.operationalize(waveletData)); } return wave; }
@Override public Collection<WaveViewData> search( ParticipantId user, String query, int startAt, int numResults) { LOG.fine( "Search query '" + query + "' from user: "******" [" + startAt + ", " + (startAt + numResults - 1) + "]"); Map<QueryHelper.TokenQueryType, Set<String>> queryParams = null; try { queryParams = queryHelper.parseQuery(query); } catch (QueryHelper.InvalidQueryException e1) { // Invalid query param - stop and return empty search results. LOG.warning("Invalid Query. " + e1.getMessage()); return Collections.emptyList(); } List<ParticipantId> withParticipantIds = null; List<ParticipantId> creatorParticipantIds = null; try { String localDomain = user.getDomain(); // Build and validate. withParticipantIds = QueryHelper.buildValidatedParticipantIds( queryParams, QueryHelper.TokenQueryType.WITH, localDomain); creatorParticipantIds = QueryHelper.buildValidatedParticipantIds( queryParams, QueryHelper.TokenQueryType.CREATOR, localDomain); } catch (InvalidParticipantAddress e) { // Invalid address - stop and return empty search results. LOG.warning("Invalid participantId: " + e.getAddress() + " in query: " + query); return Collections.emptyList(); } // Maybe should be changed in case other folders in addition to 'inbox' are added. boolean isAllQuery = !queryParams.containsKey(QueryHelper.TokenQueryType.IN); // Must use a map with stable ordering, since indices are meaningful. Map<WaveId, WaveViewData> results = Maps.newLinkedHashMap(); for (Map.Entry<WaveId, Wave> entry : waves.entrySet()) { WaveId waveId = entry.getKey(); Wave wave = entry.getValue(); WaveViewData view = null; // Copy of the wave built up for search hits. for (WaveletContainer c : wave) { // 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. ParticipantId sharedDomainParticipantId = c.getSharedDomainParticipant(); try { // TODO (Yuri Z.) Need to explore how to avoid this copy, e.g., by // moving parts of the matches() logic into a WaveletContainer method. ObservableWaveletData wavelet = c.copyWaveletData(); // Only filtering by participants is implemented for now. if (!matches( wavelet, user, sharedDomainParticipantId, withParticipantIds, creatorParticipantIds, isAllQuery)) { continue; } if (view == null) { view = WaveViewDataImpl.create(waveId); } // Just keep adding all the relevant wavelets in this wave. view.addWavelet(wavelet); } catch (WaveletStateException e) { LOG.warning("Failed to access wavelet " + c.getWaveletName(), e); } } // Filter out waves without conversational root wavelet from search result. if (WaveletDataUtil.hasConversationalRootWavelet(view)) { results.put(waveId, view); } } List<WaveViewData> searchResultslist = null; int searchResultSize = results.values().size(); // Check if we have enough results to return. if (searchResultSize < startAt) { searchResultslist = Collections.emptyList(); } else { int endAt = Math.min(startAt + numResults, searchResultSize); searchResultslist = QueryHelper.computeSorter(queryParams) .sortedCopy(results.values()) .subList(startAt, endAt); } LOG.info( "Search response to '" + query + "': " + searchResultslist.size() + " results, user: " + user); // Memory management wise it's dangerous to return a sublist of a much // longer list, therefore, we return a 'defensive' copy. return ImmutableList.copyOf(searchResultslist); }
@Override public int compare(WaveViewData arg0, WaveViewData arg1) { return arg0.getWaveId().compareTo(arg1.getWaveId()); }