/* * * Copyright (C) 2007-2015 Licensed to the Comunes Association (CA) under * one or more contributor license agreements (see COPYRIGHT for details). * The CA licenses this file to you under the GNU Affero General Public * License version 3, (the "License"); you may not use this file except in * compliance with the License. This file is part of kune. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package cc.kune.wave.server.search; import java.io.Closeable; import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.persistence.NoResultException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.waveprotocol.box.server.waveserver.PerUserWaveViewHandler; import org.waveprotocol.box.server.waveserver.ReadableWaveletDataProvider; import org.waveprotocol.box.server.waveserver.WaveServerException; 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 cc.kune.core.server.manager.ParticipantEntityManager; import cc.kune.core.server.manager.WaveEntityManager; import cc.kune.core.server.persist.KuneTransactional; import cc.kune.domain.ParticipantEntity; import cc.kune.domain.WaveEntity; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton public class CustomPerUserWaveViewHandlerImpl implements PerUserWaveViewHandler, Closeable { // TODO Inject executor. private static final Executor executor = Executors.newSingleThreadExecutor(); public static final Log LOG = LogFactory.getLog(CustomPerUserWaveViewHandlerImpl.class); @Inject private ParticipantEntityManager participantEntityManager; @Inject private WaveEntityManager waveEntityManager; @Inject private ReadableWaveletDataProvider waveletProvider; @KuneTransactional private void addWaveToUser(final WaveEntity waveEntity, final ParticipantId participantId) { Preconditions.checkNotNull(waveEntity); LOG.debug("Added wave to participant " + participantId.getAddress()); final ParticipantEntity participant = participantEntityManager.createIfNotExist(participantId.getAddress()); waveEntityManager.add(waveEntity, participant); } @Override public void close() throws IOException { // Probably nothing to do here... } private WaveEntity getWaveEntity(final ReadableWaveletData waveletData) { WaveEntity waveEntity; final String waveId = waveletData.getWaveId().serialise(); final String waveletId = waveletData.getWaveletId().serialise(); final String domain = waveletData.getWaveId().getDomain(); final ParticipantId creator = waveletData.getCreator(); final Long creationTime = waveletData.getCreationTime(); try { waveEntity = waveEntityManager.find(domain, waveId, waveletId); } catch (final javax.persistence.NoResultException e) { waveEntity = waveEntityManager.add(domain, waveId, waveletId, waveletData.getLastModifiedTime(), participantEntityManager.createIfNotExist(creator.getAddress()), creationTime); } Preconditions.checkNotNull(waveEntity); return waveEntity; } private void logNotFound(final ParticipantId participantId) { LOG.info("Failed to find and retrieve participant " + participantId.getAddress()); } @Override public ListenableFuture<Void> onParticipantAdded(final WaveletName waveletName, final ParticipantId participantId) { Preconditions.checkNotNull(waveletName); Preconditions.checkNotNull(participantId); final ListenableFutureTask<Void> task = ListenableFutureTask.<Void> create(new Callable<Void>() { @Override @KuneTransactional public Void call() throws Exception { ReadableWaveletData waveletData; try { waveletData = waveletProvider.getReadableWaveletData(waveletName); final WaveEntity waveEntity = getWaveEntity(waveletData); addWaveToUser(waveEntity, participantId); updateWaveEntity(waveEntity, waveletData); } catch (final WaveServerException e) { LOG.error("Failed to update index for " + waveletName, e); throw e; } return null; } }); executor.execute(task); return task; } @Override public ListenableFuture<Void> onParticipantRemoved(final WaveletName waveletName, final ParticipantId participantId) { Preconditions.checkNotNull(waveletName); Preconditions.checkNotNull(participantId); final ListenableFutureTask<Void> task = ListenableFutureTask.<Void> create(new Callable<Void>() { @Override @KuneTransactional public Void call() throws Exception { ReadableWaveletData waveletData; try { waveletData = waveletProvider.getReadableWaveletData(waveletName); final WaveEntity waveEntity = getWaveEntity(waveletData); removeWaveToUser(waveEntity, participantId); updateWaveEntity(waveEntity, waveletData); } catch (final WaveServerException e) { LOG.error("Failed to update index for " + waveletName, e); throw e; } return null; } }); executor.execute(task); return task; } @Override @KuneTransactional public ListenableFuture<Void> onWaveInit(final WaveletName waveletName) { Preconditions.checkNotNull(waveletName); LOG.debug("On wave init of wave " + waveletName.toString()); try { final ReadableWaveletData waveletData = waveletProvider.getReadableWaveletData(waveletName); final WaveEntity waveEntity = getWaveEntity(waveletData); Preconditions.checkNotNull(waveEntity); for (final ParticipantId participantId : waveletData.getParticipants()) { addWaveToUser(waveEntity, participantId); } } catch (final WaveServerException e) { LOG.error("Failed to initialize index for " + waveletName, e); } final ListenableFutureTask<Void> task = ListenableFutureTask.<Void> create(new Callable<Void>() { @Override public Void call() throws Exception { return null; } }); executor.execute(task); return task; } @KuneTransactional private void removeWaveToUser(final WaveEntity waveEntity, final ParticipantId participantId) { Preconditions.checkNotNull(waveEntity); LOG.debug("Remove wave to participant " + participantId.getAddress()); final ParticipantEntity participant = participantEntityManager.createIfNotExist(participantId.getAddress()); waveEntityManager.remove(waveEntity, participant); } @Override @KuneTransactional public Multimap<WaveId, WaveletId> retrievePerUserWaveView(final ParticipantId participantId) { final String address = participantId.getAddress(); LOG.debug("Retrive waves view of user " + address); final Multimap<WaveId, WaveletId> userWavesViewMap = HashMultimap.create(); try { final ParticipantEntity participantEntity = participantEntityManager.find(address); if (participantEntity != null) { for (final WaveEntity wave : participantEntity.getWaves()) { userWavesViewMap.put(WaveId.deserialise(wave.getWaveId()), WaveletId.deserialise(wave.getWaveletId())); } } else { throw new NoResultException(); } } catch (final javax.persistence.NoResultException e) { logNotFound(participantId); } return userWavesViewMap; } private void updateWaveEntity(final WaveEntity waveEntity, final ReadableWaveletData waveletData) { waveEntityManager.setLastModifiedTime(waveEntity, waveletData.getLastModifiedTime()); } }