http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/SigningSignatureHandler.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/SigningSignatureHandler.java b/src/org/waveprotocol/box/server/waveserver/SigningSignatureHandler.java deleted file mode 100644 index f9e6cbf..0000000 --- a/src/org/waveprotocol/box/server/waveserver/SigningSignatureHandler.java +++ /dev/null @@ -1,129 +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.waveserver; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.ProvisionException; -import com.google.inject.Singleton; -import com.typesafe.config.Config; -import org.waveprotocol.wave.crypto.SignatureException; -import org.waveprotocol.wave.crypto.SignerInfo; -import org.waveprotocol.wave.crypto.WaveSigner; -import org.waveprotocol.wave.crypto.WaveSignerFactory; -import org.waveprotocol.wave.federation.Proto.ProtocolSignature; -import org.waveprotocol.wave.federation.Proto.ProtocolWaveletDelta; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.util.List; - -/** - * A signature handler that delegates to a wave signer to sign deltas. - */ -public class SigningSignatureHandler implements SignatureHandler { - /** - * Guice {@link Provider} for the instance of {@link SigningSignatureHandler} - */ - @Singleton - public static class SigningSignatureHandlerProvider implements Provider<SignatureHandler> { - private static final FileOpener FILE_OPENER = new FileOpener(); - - private String privateKey; - private List<String> certs; - private String certDomain; - private final WaveSignerFactory waveSignerFactory; - private SigningSignatureHandler signer = null; - - /** - * @param factory A {@link WaveSignerFactory}. - * @param config the configuration. - */ - @Inject - public SigningSignatureHandlerProvider(WaveSignerFactory factory, Config config) { - this.privateKey = config.getString("federation.certificate_private_key"); - this.certs = config.getStringList("federation.certificate_files"); - this.certDomain = config.getString("federation.certificate_domain"); - this.waveSignerFactory = factory; - } - - @Override - public SigningSignatureHandler get() { - synchronized (this) { - if (signer == null) { - FileInputStream privateKeyStream; - try { - privateKeyStream = new FileInputStream(privateKey); - } catch (FileNotFoundException e) { - throw new ProvisionException("could not read private key", e); - } - - Iterable<FileInputStream> certStreams = - Iterables.transform(certs, FILE_OPENER); - - try { - WaveSigner inner = waveSignerFactory.getSigner(privateKeyStream, certStreams, certDomain); - signer = new SigningSignatureHandler(inner); - } catch (SignatureException e) { - throw new ProvisionException("could not make wave signer", e); - } - } - } - return signer; - } - - // Function that turns file names into FileInputStreams - private static class FileOpener implements Function<String, FileInputStream> { - - @Override - public FileInputStream apply(String filename) { - try { - return new FileInputStream(filename); - } catch (FileNotFoundException e) { - throw new ProvisionException("could not read certificates", e); - } - } - } - } - - private final WaveSigner signer; - - public SigningSignatureHandler(WaveSigner signer) { - this.signer = signer; - } - - @Override - public String getDomain() { - return signer.getSignerInfo().getDomain(); - } - - public SignerInfo getSignerInfo() { - return signer.getSignerInfo(); - } - - @Override - public Iterable<ProtocolSignature> sign(ByteStringMessage<ProtocolWaveletDelta> delta) { - return ImmutableList.of(signer.sign(delta.getByteString().toByteArray())); - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java b/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java deleted file mode 100644 index 53f35c9..0000000 --- a/src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java +++ /dev/null @@ -1,198 +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.waveserver; - -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.inject.Inject; -import com.google.inject.name.Named; -import com.google.wave.api.SearchResult; - -import org.waveprotocol.box.server.CoreSettingsNames; -import org.waveprotocol.box.server.waveserver.QueryHelper.InvalidQueryException; -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.wave.InvalidParticipantAddress; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; -import org.waveprotocol.wave.model.wave.data.WaveViewData; -import org.waveprotocol.wave.util.logging.Log; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Search provider that reads user specific info from user data wavelet. - * - * @author [email protected] (Yuri Zelikov) - */ -public class SimpleSearchProviderImpl extends AbstractSearchProviderImpl { - - private static final Log LOG = Log.get(SimpleSearchProviderImpl.class); - - private final PerUserWaveViewProvider waveViewProvider; - - @Inject - public SimpleSearchProviderImpl(@Named(CoreSettingsNames.WAVE_SERVER_DOMAIN) final String waveDomain, - WaveDigester digester, final WaveMap waveMap, PerUserWaveViewProvider userWaveViewProvider) { - super(waveDomain, digester, waveMap); - this.waveViewProvider = userWaveViewProvider; - } - - @Override - public SearchResult search(final ParticipantId user, String query, int startAt, int numResults) { - LOG.fine("Search query '" + query + "' from user: " + user + " [" + startAt + ", " - + ((startAt + numResults) - 1) + "]"); - Map<TokenQueryType, Set<String>> queryParams = null; - try { - queryParams = QueryHelper.parseQuery(query); - } catch (InvalidQueryException e1) { - // Invalid query param - stop and return empty search results. - LOG.warning("Invalid Query. " + e1.getMessage()); - return digester.generateSearchResult(user, query, null); - } - // Maybe should be changed in case other folders in addition to 'inbox' are - // added. - final boolean isAllQuery = !queryParams.containsKey(TokenQueryType.IN); - - final List<ParticipantId> withParticipantIds; - final List<ParticipantId> creatorParticipantIds; - try { - String localDomain = user.getDomain(); - // Build and validate. - withParticipantIds = - QueryHelper.buildValidatedParticipantIds(queryParams, TokenQueryType.WITH, - localDomain); - creatorParticipantIds = - QueryHelper.buildValidatedParticipantIds(queryParams, TokenQueryType.CREATOR, - localDomain); - } catch (InvalidParticipantAddress e) { - // Invalid address - stop and return empty search results. - LOG.warning("Invalid participantId: " + e.getAddress() + " in query: " + query); - return digester.generateSearchResult(user, query, null); - } - - LinkedHashMultimap<WaveId, WaveletId> currentUserWavesView = - createWavesViewToFilter(user, isAllQuery); - Function<ReadableWaveletData, Boolean> filterWaveletsFunction = - createFilterWaveletsFunction(user, isAllQuery, withParticipantIds, creatorParticipantIds); - - ensureWavesHaveUserDataWavelet(currentUserWavesView, user); - - List<WaveViewData> results = - Lists.newArrayList(filterWavesViewBySearchCriteria(filterWaveletsFunction, - currentUserWavesView).values()); - List<WaveViewData> sortedResults = sort(queryParams, results); - - Collection<WaveViewData> searchResult = - computeSearchResult(user, startAt, numResults, sortedResults); - LOG.info("Search response to '" + query + "': " + searchResult.size() + " results, user: " - + user); - return digester.generateSearchResult(user, query, searchResult); - } - - private LinkedHashMultimap<WaveId, WaveletId> createWavesViewToFilter(final ParticipantId user, - final boolean isAllQuery) { - LinkedHashMultimap<WaveId, WaveletId> currentUserWavesView; - currentUserWavesView = LinkedHashMultimap.create(); - currentUserWavesView.putAll(waveViewProvider.retrievePerUserWaveView(user)); - if (isAllQuery) { - // If it is the "all" query - we need to include also waves view of the - // shared domain participant. - currentUserWavesView.putAll(waveViewProvider.retrievePerUserWaveView(sharedDomainParticipantId)); - } - - if(LOG.isFineLoggable()) { - for (Map.Entry<WaveId, WaveletId> e : currentUserWavesView.entries()) { - LOG.fine("unfiltered view contains: " + e.getKey() + " " + e.getValue()); - } - } - - return currentUserWavesView; - } - - private Function<ReadableWaveletData, Boolean> createFilterWaveletsFunction( - final ParticipantId user, final boolean isAllQuery, - final List<ParticipantId> withParticipantIds, final List<ParticipantId> creatorParticipantIds) { - // A function to be applied by the WaveletContainer. - Function<ReadableWaveletData, Boolean> matchesFunction = - new Function<ReadableWaveletData, Boolean>() { - - @Override - public Boolean apply(ReadableWaveletData wavelet) { - try { - return wavelet != null - && isWaveletMatchesCriteria(wavelet, user, sharedDomainParticipantId, - withParticipantIds, creatorParticipantIds, isAllQuery); - } catch (WaveletStateException e) { - LOG.warning( - "Failed to access wavelet " - + WaveletName.of(wavelet.getWaveId(), wavelet.getWaveletId()), e); - return false; - } - } - }; - return matchesFunction; - } - - /** - * Verifies whether the wavelet matches the filter criteria. - * - * @param wavelet the wavelet. - * @param user the logged in user. - * @param sharedDomainParticipantId the shared domain participant id. - * @param withList the list of participants to be used in 'with' filter. - * @param creatorList the list of participants to be used in 'creator' filter. - * @param isAllQuery true if the search results should include shared for this - * domain waves. - */ - protected boolean isWaveletMatchesCriteria(ReadableWaveletData wavelet, ParticipantId user, - ParticipantId sharedDomainParticipantId, List<ParticipantId> withList, - List<ParticipantId> creatorList, boolean isAllQuery) throws WaveletStateException { - Preconditions.checkNotNull(wavelet); - // Filter by creator. This is the fastest check so we perform it first. - for (ParticipantId creator : creatorList) { - if (!creator.equals(wavelet.getCreator())) { - // Skip. - return false; - } - } - boolean matches = - super.isWaveletMatchesCriteria(wavelet, user, sharedDomainParticipantId, isAllQuery); - // Now filter by 'with'. - for (ParticipantId otherUser : withList) { - if (!wavelet.getParticipants().contains(otherUser)) { - // Skip. - return false; - } - } - return matches; - } - - private List<WaveViewData> sort(Map<TokenQueryType, Set<String>> queryParams, - List<WaveViewData> results) { - return QueryHelper.computeSorter(queryParams).sortedCopy(results); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/SolrSearchProviderImpl.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/SolrSearchProviderImpl.java b/src/org/waveprotocol/box/server/waveserver/SolrSearchProviderImpl.java deleted file mode 100644 index 66ff288..0000000 --- a/src/org/waveprotocol/box/server/waveserver/SolrSearchProviderImpl.java +++ /dev/null @@ -1,264 +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.waveserver; - -import com.google.common.base.Function; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.inject.Inject; -import com.google.wave.api.SearchResult; -import com.typesafe.config.Config; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.http.HttpStatus; -import org.waveprotocol.box.stat.Timed; -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.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; -import org.waveprotocol.wave.model.wave.data.WaveViewData; -import org.waveprotocol.wave.util.logging.Log; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * Search provider that offers full text search - * - * @author Frank R. <[email protected]> - * @author Yuri Zelikov <[email protected]> - */ -public class SolrSearchProviderImpl extends AbstractSearchProviderImpl { - - private static final Log LOG = Log.get(SolrSearchProviderImpl.class); - - private static final String WORD_START = "(\\b|^)"; - private static final Pattern IN_PATTERN = Pattern.compile("\\bin:\\S*"); - private static final Pattern WITH_PATTERN = Pattern.compile("\\bwith:\\S*"); - - public static final int ROWS = 10; - - public static final String ID = "id"; - public static final String WAVE_ID = "waveId_s"; - public static final String WAVELET_ID = "waveletId_s"; - public static final String DOC_NAME = "docName_s"; - public static final String LMT = "lmt_l"; - public static final String WITH = "with_ss"; - public static final String WITH_FUZZY = "with_txt"; - public static final String CREATOR = "creator_t"; - public static final String TEXT = "text_t"; - public static final String IN = "in_ss"; - - private final String solrBaseUrl; - - /*- - * http://wiki.apache.org/solr/CommonQueryParameters#q - */ - public static final String Q = WAVE_ID + ":[* TO *]" - + " AND " + WAVELET_ID + ":[* TO *]" - + " AND " + DOC_NAME + ":[* TO *]" - + " AND " + LMT + ":[* TO *]" - + " AND " + WITH + ":[* TO *]" - + " AND " + WITH_FUZZY + ":[* TO *]" - + " AND " + CREATOR + ":[* TO *]"; - - private static final String FILTER_QUERY_PREFIX = "{!lucene q.op=AND df=" + TEXT + "}" // - + WITH + ":"; - - private final static Function<InputStreamReader, JsonArray> extractDocsJsonFunction = - new Function<InputStreamReader, JsonArray>() { - - @Override - public JsonArray apply(InputStreamReader inputStreamResponse) { - return extractDocsJson(inputStreamResponse); - }}; - - @Inject - public SolrSearchProviderImpl(WaveDigester digester, WaveMap waveMap, Config config) { - super(config.getString("core.wave_server_domain"), digester, waveMap); - solrBaseUrl = config.getString("core.solr_base_url"); - } - - @Timed - @Override - public SearchResult search(final ParticipantId user, String query, int startAt, int numResults) { - - LOG.fine("Search query '" + query + "' from user: " + user + " [" + startAt + ", " - + ((startAt + numResults) - 1) + "]"); - - // Maybe should be changed in case other folders in addition to 'inbox' are - // added. - final boolean isAllQuery = isAllQuery(query); - - LinkedHashMultimap<WaveId, WaveletId> currentUserWavesView = LinkedHashMultimap.create(); - - if (numResults > 0) { - - int start = startAt; - int rows = Math.max(numResults, ROWS); - - /*- - * "fq" stands for Filter Query. see - * http://wiki.apache.org/solr/CommonQueryParameters#fq - */ - String fq = buildFilterQuery(query, isAllQuery, user.getAddress(), sharedDomainParticipantId); - - try { - while (true) { - String solrQuery = buildCurrentSolrQuery(start, rows, fq); - - JsonArray docsJson = sendSearchRequest(solrQuery, extractDocsJsonFunction); - - addSearchResultsToCurrentWaveView(currentUserWavesView, docsJson); - if (docsJson.size() < rows) { - break; - } - start += rows; - } - } catch (Exception e) { - LOG.warning("Failed to execute query: " + query); - LOG.warning(e.getMessage()); - return digester.generateSearchResult(user, query, null); - } - } - - ensureWavesHaveUserDataWavelet(currentUserWavesView, user); - - LinkedHashMap<WaveId, WaveViewData> results = - createResults(user, isAllQuery, currentUserWavesView); - - Collection<WaveViewData> searchResult = - computeSearchResult(user, startAt, numResults, Lists.newArrayList(results.values())); - LOG.info("Search response to '" + query + "': " + searchResult.size() + " results, user: " - + user); - - return digester.generateSearchResult(user, query, searchResult); - } - - private LinkedHashMap<WaveId, WaveViewData> createResults(final ParticipantId user, - final boolean isAllQuery, LinkedHashMultimap<WaveId, WaveletId> currentUserWavesView) { - Function<ReadableWaveletData, Boolean> matchesFunction = - new Function<ReadableWaveletData, Boolean>() { - - @Override - public Boolean apply(ReadableWaveletData wavelet) { - try { - return isWaveletMatchesCriteria(wavelet, user, sharedDomainParticipantId, isAllQuery); - } catch (WaveletStateException e) { - LOG.warning( - "Failed to access wavelet " - + WaveletName.of(wavelet.getWaveId(), wavelet.getWaveletId()), e); - return false; - } - } - }; - - LinkedHashMap<WaveId, WaveViewData> results = - filterWavesViewBySearchCriteria(matchesFunction, currentUserWavesView); - if (LOG.isFineLoggable()) { - for (Map.Entry<WaveId, WaveViewData> e : results.entrySet()) { - LOG.fine("filtered results contains: " + e.getKey()); - } - } - return results; - } - - private void addSearchResultsToCurrentWaveView( - LinkedHashMultimap<WaveId, WaveletId> currentUserWavesView, JsonArray docsJson) { - for (JsonElement aDocsJson : docsJson) { - JsonObject docJson = aDocsJson.getAsJsonObject(); - - WaveId waveId = WaveId.deserialise(docJson.getAsJsonPrimitive(WAVE_ID).getAsString()); - WaveletId waveletId = - WaveletId.deserialise(docJson.getAsJsonPrimitive(WAVELET_ID).getAsString()); - currentUserWavesView.put(waveId, waveletId); - } - } - - private static JsonArray extractDocsJson(InputStreamReader isr) { - JsonObject json = new JsonParser().parse(isr).getAsJsonObject(); - JsonObject responseJson = json.getAsJsonObject("response"); - return responseJson.getAsJsonArray("docs"); - } - - private String buildCurrentSolrQuery(int start, int rows, String fq) { - return solrBaseUrl + "/select?wt=json" + "&start=" + start + "&rows=" - + rows + "&sort=" + LMT + "+desc" + "&q=" + Q + "&fq=" + fq; - } - - private JsonArray sendSearchRequest(String solrQuery, - Function<InputStreamReader, JsonArray> function) throws IOException { - JsonArray docsJson; - GetMethod getMethod = new GetMethod(); - HttpClient httpClient = new HttpClient(); - try { - getMethod.setURI(new URI(solrQuery, false)); - int statusCode = httpClient.executeMethod(getMethod); - docsJson = function.apply(new InputStreamReader(getMethod.getResponseBodyAsStream())); - if (statusCode != HttpStatus.SC_OK) { - LOG.warning("Failed to execute query: " + solrQuery); - throw new IOException("Search request status is not OK: " + statusCode); - } - } finally { - getMethod.releaseConnection(); - } - return docsJson; - } - - private static boolean isAllQuery(String query) { - return !IN_PATTERN.matcher(query).find(); - } - - private static String buildUserQuery(String query, ParticipantId sharedDomainParticipantId) { - return query.replaceAll(WORD_START + TokenQueryType.IN.getToken() + ":", IN + ":") - .replaceAll(WORD_START + TokenQueryType.WITH.getToken() + ":@", - WITH + ":" + sharedDomainParticipantId.getAddress()) - .replaceAll(WORD_START + TokenQueryType.WITH.getToken() + ":", WITH_FUZZY + ":") - .replaceAll(WORD_START + TokenQueryType.CREATOR.getToken() + ":", CREATOR + ":"); - } - - private static String buildFilterQuery(String query, final boolean isAllQuery, - String addressOfRequiredParticipant, ParticipantId sharedDomainParticipantId) { - - String fq; - if (isAllQuery) { - fq = - FILTER_QUERY_PREFIX + "(" + addressOfRequiredParticipant + " OR " - + sharedDomainParticipantId + ")"; - } else { - fq = FILTER_QUERY_PREFIX + addressOfRequiredParticipant; - } - if (query.length() > 0) { - - fq += " AND (" + buildUserQuery(query, sharedDomainParticipantId) + ")"; - } - return fq; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/SolrWaveIndexerImpl.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/SolrWaveIndexerImpl.java b/src/org/waveprotocol/box/server/waveserver/SolrWaveIndexerImpl.java deleted file mode 100644 index 2af772a..0000000 --- a/src/org/waveprotocol/box/server/waveserver/SolrWaveIndexerImpl.java +++ /dev/null @@ -1,304 +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.waveserver; - -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.typesafe.config.Config; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.RequestEntity; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.http.HttpStatus; -import org.waveprotocol.box.common.DeltaSequence; -import org.waveprotocol.box.common.Snippets; -import org.waveprotocol.box.server.executor.ExecutorAnnotations.SolrExecutor; -import org.waveprotocol.box.server.robots.util.ConversationUtil; -import org.waveprotocol.box.stat.Timed; -import org.waveprotocol.wave.model.document.operation.DocInitialization; -import org.waveprotocol.wave.model.id.IdUtil; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.version.HashedVersion; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.data.ReadableBlipData; -import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; -import org.waveprotocol.wave.model.waveref.WaveRef; -import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder; -import org.waveprotocol.wave.util.logging.Log; - -import java.io.IOException; -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.logging.Level; - -/** - * @author Frank R. <[email protected]> - */ -@Singleton -public class SolrWaveIndexerImpl extends AbstractWaveIndexer implements WaveBus.Subscriber, - PerUserWaveViewBus.Listener { - - private static final Log LOG = Log.get(SolrWaveIndexerImpl.class); - - private final Executor executor; - private final ReadableWaveletDataProvider waveletDataProvider; - private final String solrBaseUrl; - - - @Inject - public SolrWaveIndexerImpl(WaveMap waveMap, WaveletProvider waveletProvider, - ReadableWaveletDataProvider waveletDataProvider, ConversationUtil conversationUtil, - WaveletNotificationDispatcher notificationDispatcher, - Config config, - @SolrExecutor Executor solrExecutor) { - super(waveMap, waveletProvider); - executor = solrExecutor; - solrBaseUrl = config.getString("core.solr_base_url"); - this.waveletDataProvider = waveletDataProvider; - notificationDispatcher.subscribe(this); - } - - @Override - public ListenableFuture<Void> onParticipantAdded(final WaveletName waveletName, - ParticipantId participant) { - /* - * ignored. See waveletCommitted(WaveletName, HashedVersion) - */ - return null; - } - - @Override - public ListenableFuture<Void> onParticipantRemoved(final WaveletName waveletName, - ParticipantId participant) { - /* - * ignored. See waveletCommitted(WaveletName, HashedVersion) - */ - return null; - } - - @Override - public ListenableFuture<Void> onWaveInit(final WaveletName waveletName) { - - ListenableFutureTask<Void> task = ListenableFutureTask.create(new Callable<Void>() { - - @Override - public Void call() throws Exception { - ReadableWaveletData waveletData; - try { - waveletData = waveletDataProvider.getReadableWaveletData(waveletName); - updateIndex(waveletData); - } catch (WaveServerException e) { - LOG.log(Level.SEVERE, "Failed to initialize index for " + waveletName, e); - throw e; - } - return null; - } - }); - executor.execute(task); - return task; - } - - @Override - protected void processWavelet(WaveletName waveletName) { - onWaveInit(waveletName); - } - - @Override - protected void postIndexHook() { - try { - getWaveMap().unloadAllWavelets(); - } catch (WaveletStateException e) { - throw new IndexException("Problem encountered while cleaning up", e); - } - } - - @Timed - private void updateIndex(ReadableWaveletData wavelet) throws IndexException { - Preconditions.checkNotNull(wavelet); - if (IdUtil.isConversationalId(wavelet.getWaveletId())) { - JsonArray docsJson = buildJsonDoc(wavelet); - postUpdateToSolr(wavelet, docsJson); - } - } - - private void postUpdateToSolr(ReadableWaveletData wavelet, JsonArray docsJson) { - PostMethod postMethod = - new PostMethod(solrBaseUrl + "/update/json?commit=true"); - try { - RequestEntity requestEntity = - new StringRequestEntity(docsJson.toString(), "application/json", "UTF-8"); - postMethod.setRequestEntity(requestEntity); - - HttpClient httpClient = new HttpClient(); - int statusCode = httpClient.executeMethod(postMethod); - if (statusCode != HttpStatus.SC_OK) { - throw new IndexException(wavelet.getWaveId().serialise()); - } - } catch (IOException e) { - throw new IndexException(String.valueOf(wavelet.getWaveletId()), e); - } finally { - postMethod.releaseConnection(); - } - } - - JsonArray buildJsonDoc(ReadableWaveletData wavelet) { - JsonArray docsJson = new JsonArray(); - - String waveletId = wavelet.getWaveletId().serialise(); - String modified = Long.toString(wavelet.getLastModifiedTime()); - String creator = wavelet.getCreator().getAddress(); - - for (String docName : wavelet.getDocumentIds()) { - ReadableBlipData document = wavelet.getDocument(docName); - - if (!IdUtil.isBlipId(docName)) { - continue; - } - - Iterable<DocInitialization> ops = Lists.newArrayList(document.getContent().asOperation()); - String text = Snippets.collateTextForOps(ops, new Function<StringBuilder, Void>() { - - @Override - public Void apply(StringBuilder resultBuilder) { - resultBuilder.append("\n"); - return null; - } - - }); - - JsonArray participantsJson = new JsonArray(); - for (ParticipantId participant : wavelet.getParticipants()) { - String participantAddress = participant.toString(); - participantsJson.add(new JsonPrimitive(participantAddress)); - } - - String id = - JavaWaverefEncoder.encodeToUriPathSegment(WaveRef.of(wavelet.getWaveId(), - wavelet.getWaveletId(), docName)); - - JsonObject docJson = new JsonObject(); - docJson.addProperty(SolrSearchProviderImpl.ID, id); - docJson.addProperty(SolrSearchProviderImpl.WAVE_ID, wavelet.getWaveId().serialise()); - docJson.addProperty(SolrSearchProviderImpl.WAVELET_ID, waveletId); - docJson.addProperty(SolrSearchProviderImpl.DOC_NAME, docName); - docJson.addProperty(SolrSearchProviderImpl.LMT, modified); - docJson.add(SolrSearchProviderImpl.WITH, participantsJson); - docJson.add(SolrSearchProviderImpl.WITH_FUZZY, participantsJson); - docJson.addProperty(SolrSearchProviderImpl.CREATOR, creator); - docJson.addProperty(SolrSearchProviderImpl.TEXT, text); - docJson.addProperty(SolrSearchProviderImpl.IN, "inbox"); - - docsJson.add(docJson); - } - return docsJson; - } - - @Override - public void waveletUpdate(final ReadableWaveletData wavelet, DeltaSequence deltas) { - /* - * Overridden out for optimization, see waveletCommitted(WaveletName, - * HashedVersion) - */ - } - - @Override - public void waveletCommitted(final WaveletName waveletName, final HashedVersion version) { - - Preconditions.checkNotNull(waveletName); - - ListenableFutureTask<Void> task = ListenableFutureTask.create(new Callable<Void>() { - - @Override - public Void call() throws Exception { - ReadableWaveletData waveletData; - try { - waveletData = waveletDataProvider.getReadableWaveletData(waveletName); - LOG.fine("commit " + version + " " + waveletData.getVersion()); - if (waveletData.getVersion() == version.getVersion()) { - updateIndex(waveletData); - } - } catch (WaveServerException e) { - LOG.log(Level.SEVERE, "Failed to update index for " + waveletName, e); - throw e; - } - return null; - } - }); - executor.execute(task); - } - - @Override - public synchronized void remakeIndex() throws WaveServerException { - - /*- - * To fully rebuild the index, need to delete everything first - * the <query> tag should contain the value of - * org.waveprotocol.box.server.waveserver.SolrSearchProviderImpl.Q - * - * http://localhost:8983/solr/update?stream.body=<delete><query>waveId_s:[*%20TO%20*]%20AND%20waveletId_s:[*%20TO%20*]%20AND%20docName_s:[*%20TO%20*]%20AND%20lmt_l:[*%20TO%20*]%20AND%20with_ss:[*%20TO%20*]%20AND%20with_txt:[*%20TO%20*]%20AND%20creator_t:[*%20TO%20*]</query></delete> - * http://localhost:8983/solr/update?stream.body=<commit/> - * - * see - * http://wiki.apache.org/solr/FAQ#How_can_I_delete_all_documents_from_my_index.3F - */ - - sendRequestToDeleteSolrIndex(); - super.remakeIndex(); - } - - private void sendRequestToDeleteSolrIndex() { - GetMethod getMethod = new GetMethod(); - try { - getMethod - .setURI(new URI(solrBaseUrl + "/update?wt=json" - + "&stream.body=<delete><query>" + SolrSearchProviderImpl.Q + "</query></delete>", - false)); - - HttpClient httpClient = new HttpClient(); - int statusCode = httpClient.executeMethod(getMethod); - if (statusCode == HttpStatus.SC_OK) { - getMethod.setURI(new URI(solrBaseUrl + "/update?wt=json" - + "&stream.body=<commit/>", false)); - - httpClient = new HttpClient(); - statusCode = httpClient.executeMethod(getMethod); - if (statusCode != HttpStatus.SC_OK) { - LOG.warning("failed to clean solr index"); - } - } else { - LOG.warning("failed to clean solr index"); - } - } catch (Exception e) { - LOG.warning("failed to clean solr index", e); - } finally { - getMethod.releaseConnection(); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/TextCollator.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/TextCollator.java b/src/org/waveprotocol/box/server/waveserver/TextCollator.java deleted file mode 100644 index aea54eb..0000000 --- a/src/org/waveprotocol/box/server/waveserver/TextCollator.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.waveprotocol.box.server.waveserver; - -import com.google.inject.ImplementedBy; - -import org.waveprotocol.box.common.Snippets; -import org.waveprotocol.box.server.waveserver.TextCollator.SnippetTextCollatorImpl; -import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; - -/** - * Adapter interface that provdes simpler access to {@link Snippet} methods. - * - * @author [email protected] (Yuri Zelikov) - */ -@ImplementedBy(SnippetTextCollatorImpl.class) -public interface TextCollator { - String collateTextForWavelet(ReadableWaveletData waveletData); - - static class SnippetTextCollatorImpl implements TextCollator { - - @Override - public String collateTextForWavelet(ReadableWaveletData waveletData) { - return Snippets.collateTextForWavelet(waveletData); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/TokenQueryType.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/TokenQueryType.java b/src/org/waveprotocol/box/server/waveserver/TokenQueryType.java deleted file mode 100644 index 6546350..0000000 --- a/src/org/waveprotocol/box/server/waveserver/TokenQueryType.java +++ /dev/null @@ -1,76 +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.waveserver; - -import java.util.HashMap; -import java.util.Map; - -/** - * Valid search query types. - * - * @author [email protected] (Yuri Zelikov) - */ -public enum TokenQueryType { - IN("in"), - ORDERBY("orderby"), - WITH("with"), - CREATOR("creator"), - ID("id"), - ; - - final String token; - - TokenQueryType(String token) { - this.token = token; - } - - String getToken() { - return token; - } - - private static final Map<String, TokenQueryType> reverseLookupMap = - new HashMap<String, TokenQueryType>(); - static { - for (TokenQueryType type : TokenQueryType.values()) { - reverseLookupMap.put(type.getToken(), type); - } - } - - /** - * Looks up the type by the string token. - * - * @param token the token in the search, like: "in" or "with". - * @return the corresponding TokenType. - */ - public static TokenQueryType fromToken(String token) { - TokenQueryType qyeryToken = reverseLookupMap.get(token); - if (qyeryToken == null) { - throw new IllegalArgumentException("Illegal query param: " + token); - } - return reverseLookupMap.get(token); - } - - /** - * @return true if there such token in the enum, false otherwise. - */ - public static boolean hasToken(String token) { - return reverseLookupMap.keySet().contains(token); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/Wave.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/Wave.java b/src/org/waveprotocol/box/server/waveserver/Wave.java deleted file mode 100644 index 815f814..0000000 --- a/src/org/waveprotocol/box/server/waveserver/Wave.java +++ /dev/null @@ -1,168 +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.waveserver; - -import com.google.common.base.Preconditions; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; -import com.google.common.util.concurrent.ListenableFuture; - -import org.waveprotocol.box.server.persistence.PersistenceException; -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.ExecutionException; - -/** - * The wavelets in a wave. - * - * @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> extends CacheLoader<WaveletId, T> { - private final WaveletContainer.Factory<T> factory; - - private final String waveDomain; - - public WaveletCreator(WaveletContainer.Factory<T> factory, String waveDomain) { - this.factory = factory; - this.waveDomain = waveDomain; - } - - @Override - public T load(WaveletId waveletId) { - return factory.create(notifiee, WaveletName.of(waveId, waveletId), waveDomain); - } - } - - private final WaveId waveId; - /** Future providing already-existing wavelets in storage. */ - private final ListenableFuture<ImmutableSet<WaveletId>> lookedupWavelets; - private final LoadingCache<WaveletId, LocalWaveletContainer> localWavelets; - private final LoadingCache<WaveletId, RemoteWaveletContainer> remoteWavelets; - private final WaveletNotificationSubscriber notifiee; - - /** - * Creates a wave. The {@code lookupWavelets} future is examined only when a - * query is first made. - */ - public Wave(WaveId waveId, - ListenableFuture<ImmutableSet<WaveletId>> lookedupWavelets, - WaveletNotificationSubscriber notifiee, LocalWaveletContainer.Factory localFactory, - RemoteWaveletContainer.Factory remoteFactory, - String waveDomain) { - this.waveId = waveId; - this.lookedupWavelets = lookedupWavelets; - this.notifiee = notifiee; - - this.localWavelets = CacheBuilder.newBuilder().build( - new WaveletCreator<LocalWaveletContainer>(localFactory, waveDomain)); - this.remoteWavelets = CacheBuilder.newBuilder().build( - new WaveletCreator<RemoteWaveletContainer>(remoteFactory, waveDomain)); - } - - @Override - public Iterator<WaveletContainer> iterator() { - return Iterators.unmodifiableIterator( - Iterables.concat(localWavelets.asMap().values(), remoteWavelets.asMap().values()).iterator()); - } - - LocalWaveletContainer getLocalWavelet(WaveletId waveletId) - throws WaveletStateException { - return getWavelet(waveletId, localWavelets); - } - - RemoteWaveletContainer getRemoteWavelet(WaveletId waveletId) - throws WaveletStateException { - return getWavelet(waveletId, remoteWavelets); - } - - LocalWaveletContainer getOrCreateLocalWavelet(WaveletId waveletId) { - try { - return localWavelets.get(waveletId); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - - RemoteWaveletContainer getOrCreateRemoteWavelet(WaveletId waveletId) { - try { - return remoteWavelets.get(waveletId); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - - private <T extends WaveletContainer> T getWavelet(WaveletId waveletId, - LoadingCache<WaveletId, T> waveletsMap) throws WaveletStateException { - ImmutableSet<WaveletId> storedWavelets; - try { - storedWavelets = - FutureUtil.getResultOrPropagateException(lookedupWavelets, PersistenceException.class); - } catch (PersistenceException e) { - throw new WaveletStateException( - "Failed to lookup wavelet " + WaveletName.of(waveId, waveletId), e); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - 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.getIfPresent(waveletId) != null) { - LOG.fine("Wavelet is in wavletsMap"); - } - } - } - - // Since waveletsMap is a computing map, we must call getIfPresent(waveletId) - // to tell if waveletId is mapped, we cannot test if get(waveletId) returns null. - if (storedWavelets != null && !storedWavelets.contains(waveletId) - && waveletsMap.getIfPresent(waveletId) == null) { - return null; - } else { - try { - T wavelet = waveletsMap.get(waveletId); - return wavelet; - } catch (CacheLoader.InvalidCacheLoadException ex) { - return null; - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - } - - ListenableFuture<ImmutableSet<WaveletId>> getLookedupWavelets() { - return lookedupWavelets; - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/WaveBus.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/WaveBus.java b/src/org/waveprotocol/box/server/waveserver/WaveBus.java deleted file mode 100644 index 1d2fa88..0000000 --- a/src/org/waveprotocol/box/server/waveserver/WaveBus.java +++ /dev/null @@ -1,65 +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.waveserver; - -import org.waveprotocol.box.common.DeltaSequence; -import org.waveprotocol.wave.model.id.WaveletName; -import org.waveprotocol.wave.model.version.HashedVersion; -import org.waveprotocol.wave.model.wave.data.ReadableWaveletData; - -/** - * Provides a subscription service for changes to wavelets. - * - * @author [email protected] (Alex North) - */ -public interface WaveBus { - /** - * Receives wave bus messages. - */ - interface Subscriber { - /** - * Notifies the subscriber of a wavelet update. - * - * @param wavelet the state of the wavelet after the deltas have - * been applied - * @param deltas deltas applied to the wavelet - */ - void waveletUpdate(ReadableWaveletData wavelet, DeltaSequence deltas); - - /** - * Notifies the subscriber that a wavelet has been committed to persistent - * storage. - * - * @param waveletName name of wavelet - * @param version the version and hash of the wavelet as it was committed - */ - void waveletCommitted(WaveletName waveletName, HashedVersion version); - } - - /** - * Subscribes to the bus, if the subscriber is not already subscribed. - */ - void subscribe(Subscriber s); - - /** - * Unsubscribes from the bus, if the subscriber is currently subscribed. - */ - void unsubscribe(Subscriber s); -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/WaveDigester.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/WaveDigester.java b/src/org/waveprotocol/box/server/waveserver/WaveDigester.java deleted file mode 100644 index b17b571..0000000 --- a/src/org/waveprotocol/box/server/waveserver/WaveDigester.java +++ /dev/null @@ -1,252 +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.waveserver; - -import com.google.common.annotations.VisibleForTesting; -import com.google.inject.Inject; -import com.google.wave.api.ApiIdSerializer; -import com.google.wave.api.SearchResult; -import com.google.wave.api.SearchResult.Digest; - -import org.waveprotocol.box.common.Snippets; -import org.waveprotocol.box.server.robots.util.ConversationUtil; -import org.waveprotocol.wave.model.conversation.BlipIterators; -import org.waveprotocol.wave.model.conversation.ConversationBlip; -import org.waveprotocol.wave.model.conversation.ObservableConversation; -import org.waveprotocol.wave.model.conversation.ObservableConversationBlip; -import org.waveprotocol.wave.model.conversation.ObservableConversationView; -import org.waveprotocol.wave.model.conversation.TitleHelper; -import org.waveprotocol.wave.model.conversation.WaveletBasedConversation; -import org.waveprotocol.wave.model.document.Document; -import org.waveprotocol.wave.model.id.IdUtil; -import org.waveprotocol.wave.model.id.ModernIdSerialiser; -import org.waveprotocol.wave.model.id.WaveletId; -import org.waveprotocol.wave.model.supplement.PrimitiveSupplement; -import org.waveprotocol.wave.model.supplement.PrimitiveSupplementImpl; -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.util.CollectionUtils; -import org.waveprotocol.wave.model.wave.ParticipantId; -import org.waveprotocol.wave.model.wave.data.ObservableWaveletData; -import org.waveprotocol.wave.model.wave.data.WaveViewData; -import org.waveprotocol.wave.model.wave.data.WaveletData; -import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * Generates digests for the search service. - * - * @author [email protected] - */ -public class WaveDigester { - - private final ConversationUtil conversationUtil; - private static final int DIGEST_SNIPPET_LENGTH = 140; - private static final int PARTICIPANTS_SNIPPET_LENGTH = 5; - private static final String EMPTY_WAVELET_TITLE = ""; - - @Inject - public WaveDigester(ConversationUtil conversationUtil) { - this.conversationUtil = conversationUtil; - } - - public SearchResult generateSearchResult(ParticipantId participant, String query, - Collection<WaveViewData> results) { - // Generate exactly one digest per wave. This includes conversational and - // non-conversational waves. The position-based API for search prevents the - // luxury of extra filtering here. Filtering can only be done in the - // searchProvider. All waves returned by the search provider must be - // included in the search result. - SearchResult result = new SearchResult(query); - if (results == null) { - return result; - } - for (WaveViewData wave : results) { - result.addDigest(build(participant, wave)); - } - - assert result.getDigests().size() == results.size(); - return result; - } - - public Digest build(ParticipantId participant, WaveViewData wave) { - - Digest digest; - - // Note: the indexing infrastructure only supports single-conversation - // waves, and requires raw wavelet access for snippeting. - ObservableWaveletData root = null; - ObservableWaveletData other = null; - ObservableWaveletData udw = null; - for (ObservableWaveletData waveletData : wave.getWavelets()) { - WaveletId waveletId = waveletData.getWaveletId(); - if (IdUtil.isConversationRootWaveletId(waveletId)) { - root = waveletData; - } else if (IdUtil.isConversationalId(waveletId)) { - other = waveletData; - } else if (IdUtil.isUserDataWavelet(waveletId) - && waveletData.getCreator().equals(participant)) { - udw = waveletData; - } - } - - ObservableWaveletData convWavelet = root != null ? root : other; - SupplementedWave supplement = null; - ObservableConversationView conversations = null; - if (convWavelet != null) { - OpBasedWavelet wavelet = OpBasedWavelet.createReadOnly(convWavelet); - if (WaveletBasedConversation.waveletHasConversation(wavelet)) { - conversations = conversationUtil.buildConversation(wavelet); - supplement = buildSupplement(participant, conversations, udw); - } - } - if (conversations != null) { - // This is a conversational wave. Produce a conversational digest. - digest = generateDigest(conversations, supplement, convWavelet); - } else { - // It is unknown how to present this wave. - digest = generateEmptyorUnknownDigest(wave); - } - - return digest; - } - - /** - * Produces a digest for a set of conversations. Never returns null. - * - * @param conversations the conversation. - * @param supplement the supplement that allows to easily perform various - * queries on user related state of the wavelet. - * @param rawWaveletData the waveletData from which the digest is generated. - * This wavelet is a copy. - * @return the server representation of the digest for the query. - */ - Digest generateDigest(ObservableConversationView conversations, SupplementedWave supplement, - WaveletData rawWaveletData) { - ObservableConversation rootConversation = conversations.getRoot(); - ObservableConversationBlip firstBlip = null; - if ((rootConversation != null) && (rootConversation.getRootThread() != null) - && (rootConversation.getRootThread().getFirstBlip() != null)) { - firstBlip = rootConversation.getRootThread().getFirstBlip(); - } - String title; - if (firstBlip != null) { - Document firstBlipContents = firstBlip.getContent(); - title = TitleHelper.extractTitle(firstBlipContents).trim(); - } else { - title = EMPTY_WAVELET_TITLE; - } - - String snippet = Snippets.renderSnippet(rawWaveletData, DIGEST_SNIPPET_LENGTH).trim(); - if (snippet.startsWith(title) && !title.isEmpty()) { - // Strip the title from the snippet if the snippet starts with the title. - snippet = snippet.substring(title.length()); - } - String waveId = ApiIdSerializer.instance().serialiseWaveId(rawWaveletData.getWaveId()); - List<String> participants = CollectionUtils.newArrayList(); - for (ParticipantId p : rawWaveletData.getParticipants()) { - if (participants.size() < PARTICIPANTS_SNIPPET_LENGTH) { - participants.add(p.getAddress()); - } else { - break; - } - } - int unreadCount = 0; - int blipCount = 0; - long lastModified = -1; - for (ConversationBlip blip : BlipIterators.breadthFirst(rootConversation)) { - if (supplement.isUnread(blip)) { - unreadCount++; - } - lastModified = Math.max(blip.getLastModifiedTime(), lastModified); - blipCount++; - } - return new Digest(title, snippet, waveId, participants, lastModified, - rawWaveletData.getCreationTime(), unreadCount, blipCount); - } - - /** @return a digest for an empty wave. */ - private Digest emptyDigest(WaveViewData wave) { - String title = ModernIdSerialiser.INSTANCE.serialiseWaveId(wave.getWaveId()); - String id = ApiIdSerializer.instance().serialiseWaveId(wave.getWaveId()); - return new Digest(title, "(empty)", id, Collections.<String> emptyList(), -1L, -1L, 0, 0); - } - - /** @return a digest for an unrecognised type of wave. */ - private Digest unknownDigest(WaveViewData wave) { - String title = ModernIdSerialiser.INSTANCE.serialiseWaveId(wave.getWaveId()); - String id = ApiIdSerializer.instance().serialiseWaveId(wave.getWaveId()); - long lmt = -1L; - long created = -1L; - int docs = 0; - List<String> participants = new ArrayList<String>(); - for (WaveletData data : wave.getWavelets()) { - lmt = Math.max(lmt, data.getLastModifiedTime()); - created = Math.max(lmt, data.getCreationTime()); - docs += data.getDocumentIds().size(); - - for (ParticipantId p : data.getParticipants()) { - if (participants.size() < PARTICIPANTS_SNIPPET_LENGTH) { - participants.add(p.getAddress()); - } else { - break; - } - } - } - return new Digest(title, "(unknown)", id, participants, lmt, created, 0, docs); - } - - /** - * Generates an empty digest in case the wave is empty, or an unknown digest - * otherwise. - * - * @param wave the wave. - * @return the generated digest. - */ - Digest generateEmptyorUnknownDigest(WaveViewData wave) { - boolean empty = !wave.getWavelets().iterator().hasNext(); - Digest digest = empty ? emptyDigest(wave) : unknownDigest(wave); - return digest; - } - - /** - * Builds the supplement model from a wave. Never returns null. - * - * @param viewer the participant for which the supplement is constructed. - * @param conversations conversations in the wave - * @param udw the user data wavelet for the logged user. - * @return the wave supplement. - */ - @VisibleForTesting - SupplementedWave buildSupplement(ParticipantId viewer, ObservableConversationView conversations, - ObservableWaveletData udw) { - // Use mock state if there is no UDW. - PrimitiveSupplement udwState = - udw != null ? WaveletBasedSupplement.create(OpBasedWavelet.createReadOnly(udw)) - : new PrimitiveSupplementImpl(); - return SupplementedWaveImpl.create(udwState, conversations, viewer, DefaultFollow.ALWAYS); - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/WaveIndexer.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/WaveIndexer.java b/src/org/waveprotocol/box/server/waveserver/WaveIndexer.java deleted file mode 100644 index a161739..0000000 --- a/src/org/waveprotocol/box/server/waveserver/WaveIndexer.java +++ /dev/null @@ -1,37 +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.waveserver; - -/** - * Provides interface for initialization of indexing logic. - * - * @author [email protected] (Yuri Zelikov) - */ -public interface WaveIndexer { - - /** - * Performs index re-making logic for specific implementation of - * {@link WaveIndexer}. When working with indexed search will do nothing. - * - * @throws WaveletStateException if something goes wrong. - * @throws WaveServerException if something goes wrong. - */ - void remakeIndex() throws WaveletStateException, WaveServerException; -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/WaveMap.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/WaveMap.java b/src/org/waveprotocol/box/server/waveserver/WaveMap.java deleted file mode 100644 index b2fa769..0000000 --- a/src/org/waveprotocol/box/server/waveserver/WaveMap.java +++ /dev/null @@ -1,201 +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.waveserver; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; -import com.google.inject.Inject; -import com.google.inject.name.Named; -import org.waveprotocol.box.common.ExceptionalIterator; -import org.waveprotocol.box.server.CoreSettingsNames; -import org.waveprotocol.box.server.executor.ExecutorAnnotations.LookupExecutor; -import org.waveprotocol.box.server.persistence.PersistenceException; -import org.waveprotocol.wave.model.id.WaveId; -import org.waveprotocol.wave.model.id.WaveletId; -import org.waveprotocol.wave.model.id.WaveletName; - -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; - -/** - * A collection of wavelets, local and remote, held in memory. - * - * @author [email protected] (Soren Lassen) - */ -public class WaveMap { - - /** - * Returns a future whose result is the ids of stored wavelets in the given wave. - * Any failure is reported as a {@link PersistenceException}. - */ - private static ListenableFuture<ImmutableSet<WaveletId>> lookupWavelets( - final WaveId waveId, final WaveletStore<?> waveletStore, Executor lookupExecutor) { - ListenableFutureTask<ImmutableSet<WaveletId>> task = - ListenableFutureTask.create( - new Callable<ImmutableSet<WaveletId>>() { - @Override - public ImmutableSet<WaveletId> call() throws PersistenceException { - return waveletStore.lookup(waveId); - } - }); - lookupExecutor.execute(task); - return task; - } - - private final LoadingCache<WaveId, Wave> waves; - private final WaveletStore<?> store; - - @Inject - public WaveMap(final DeltaAndSnapshotStore waveletStore, - final WaveletNotificationSubscriber notifiee, - final LocalWaveletContainer.Factory localFactory, - final RemoteWaveletContainer.Factory remoteFactory, - @Named(CoreSettingsNames.WAVE_SERVER_DOMAIN) final String waveDomain, - @LookupExecutor final Executor lookupExecutor) { - // NOTE(anorth): DeltaAndSnapshotStore is more specific than necessary, but - // helps Guice out. - this.store = waveletStore; - waves = CacheBuilder.newBuilder().build(new CacheLoader<WaveId, Wave>() { - @Override - public Wave load(WaveId waveId) { - ListenableFuture<ImmutableSet<WaveletId>> lookedupWavelets = - lookupWavelets(waveId, waveletStore, lookupExecutor); - return new Wave(waveId, lookedupWavelets, notifiee, localFactory, remoteFactory, - waveDomain); - } - }); - } - - /** - * Loads all wavelets from storage. - * - * @throws WaveletStateException if storage access fails. - */ - public void loadAllWavelets() throws WaveletStateException { - try { - ExceptionalIterator<WaveId, PersistenceException> itr = store.getWaveIdIterator(); - while (itr.hasNext()) { - WaveId waveId = itr.next(); - lookupWavelets(waveId); - } - } catch (PersistenceException e) { - throw new WaveletStateException("Failed to scan waves", e); - } - } - - /** - * Unloads all wavelets from memory. - * - * @throws WaveletStateException if storage access fails. - */ - public void unloadAllWavelets() throws WaveletStateException { - waves.asMap().clear(); - } - - /** - * Returns defensive copy of the map that holds waves. - */ - Map<WaveId, Wave> getWaves() { - return ImmutableMap.copyOf(waves.asMap()); - } - - public ExceptionalIterator<WaveId, WaveServerException> getWaveIds() { - Iterator<WaveId> inner = waves.asMap().keySet().iterator(); - return ExceptionalIterator.FromIterator.create(inner); - } - - public ImmutableSet<WaveletId> lookupWavelets(WaveId waveId) throws WaveletStateException { - try { - ListenableFuture<ImmutableSet<WaveletId>> future = waves.get(waveId).getLookedupWavelets(); - return FutureUtil.getResultOrPropagateException(future, PersistenceException.class); - } catch (PersistenceException e) { - throw new WaveletStateException("Failed to look up wave " + waveId, e); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new WaveletStateException("Interrupted while looking up wave " + waveId, e); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Tries to fetch the wavelet as remote, if not found - fetches as local - * wavelet. - * - * @param waveletName the wavelet name - * @return the local or remote wavelet. - * @throws WaveletStateException if something goes wrong - */ - public WaveletContainer getWavelet(WaveletName waveletName) throws WaveletStateException { - WaveletContainer waveletContainer = null; - try { - waveletContainer = getRemoteWavelet(waveletName); - } catch (WaveletStateException | NullPointerException e) { - // Ignored. - } - - if (waveletContainer == null) { - waveletContainer = getLocalWavelet(waveletName); - } - return waveletContainer; - } - - public LocalWaveletContainer getLocalWavelet(WaveletName waveletName) - throws WaveletStateException { - try { - return waves.get(waveletName.waveId).getLocalWavelet(waveletName.waveletId); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - - public RemoteWaveletContainer getRemoteWavelet(WaveletName waveletName) - throws WaveletStateException { - try { - return waves.get(waveletName.waveId).getRemoteWavelet(waveletName.waveletId); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - - public LocalWaveletContainer getOrCreateLocalWavelet(WaveletName waveletName) { - try { - return waves.get(waveletName.waveId).getOrCreateLocalWavelet(waveletName.waveletId); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } - - public RemoteWaveletContainer getOrCreateRemoteWavelet(WaveletName waveletName) { - try { - return waves.get(waveletName.waveId).getOrCreateRemoteWavelet(waveletName.waveletId); - } catch (ExecutionException ex) { - throw new RuntimeException(ex); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/7d8609e7/src/org/waveprotocol/box/server/waveserver/WaveServerException.java ---------------------------------------------------------------------- diff --git a/src/org/waveprotocol/box/server/waveserver/WaveServerException.java b/src/org/waveprotocol/box/server/waveserver/WaveServerException.java deleted file mode 100644 index 2842d9e..0000000 --- a/src/org/waveprotocol/box/server/waveserver/WaveServerException.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.waveprotocol.box.server.waveserver; - -/** - * Generic exception for use in the wave server. - * - */ -public class WaveServerException extends Exception { - - /** don't use the empty constructor. */ - @SuppressWarnings("unused") - private WaveServerException() {} - - public WaveServerException(String message) { - super(message); - } - - public WaveServerException(Throwable cause) { - super(cause); - } - - public WaveServerException(String message, Throwable cause) { - super(message, cause); - } - -}
