/*
* 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.apache.sling.discovery.impl.setup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.ObservationManager;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.testing.jcr.RepositoryProvider;
import org.apache.sling.discovery.base.commons.BaseDiscoveryService;
import org.apache.sling.discovery.base.commons.ClusterViewService;
import org.apache.sling.discovery.base.commons.UndefinedClusterViewException;
import org.apache.sling.discovery.base.commons.ViewChecker;
import org.apache.sling.discovery.base.its.setup.ModifiableTestBaseConfig;
import org.apache.sling.discovery.base.its.setup.VirtualInstance;
import org.apache.sling.discovery.base.its.setup.VirtualInstanceBuilder;
import org.apache.sling.discovery.base.its.setup.mock.DummyResourceResolverFactory;
import org.apache.sling.discovery.commons.providers.spi.base.SyncTokenService;
import org.apache.sling.discovery.impl.DiscoveryServiceImpl;
import org.apache.sling.discovery.impl.cluster.ClusterViewServiceImpl;
import org.apache.sling.discovery.impl.cluster.voting.VotingHandler;
import org.apache.sling.discovery.impl.common.heartbeat.HeartbeatHandler;
import org.apache.sling.discovery.impl.common.resource.EstablishedInstanceDescription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FullJR2VirtualInstanceBuilder extends VirtualInstanceBuilder {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private String path;
private TestConfig config;
private Object[] additionalServices;
private VotingEventListener observationListener;
private ObservationManager observationManager;
private VotingHandler votingHandler;
private SyncTokenService syncTokenService;
@Override
public VirtualInstanceBuilder createNewRepository() throws Exception {
DummyResourceResolverFactory dummyFactory = new DummyResourceResolverFactory();
dummyFactory.setArtificialDelay(delay);
this.factory = dummyFactory;
return this;
}
@Override
public VirtualInstanceBuilder useRepositoryOf(VirtualInstanceBuilder other) throws Exception {
super.useRepositoryOf(other);
DummyResourceResolverFactory dummyFactory = new DummyResourceResolverFactory();
DummyResourceResolverFactory originalFactory = (DummyResourceResolverFactory) this.factory;
// force repository to be created now..
originalFactory.getServiceResourceResolver(null);
dummyFactory.setSlingRepository(originalFactory.getSlingRepository());
dummyFactory.setArtificialDelay(getDelay());
this.factory = dummyFactory;
return this;
}
@Override
public VirtualInstanceBuilder setPath(String path) {
if (ownRepository) {
// then that's fine
this.path = path;
} else {
// then that's not fine
throw new IllegalStateException("cannot set path on inherited repo");
}
return this;
}
TestConfig getConfig() {
if (config==null) {
config = createConfig();
}
return config;
}
private TestConfig createConfig() {
TestConfig c = new TestConfig(path);
return c;
}
@Override
public ModifiableTestBaseConfig getConnectorConfig() {
return getConfig();
}
@Override
protected ViewChecker createViewChecker() throws Exception {
return HeartbeatHandler.testConstructor(getSlingSettingsService(), getResourceResolverFactory(), getAnnouncementRegistry(), getConnectorRegistry(), getConfig(), getScheduler(), getVotingHandler());
}
private SyncTokenService getSyncTokenService() throws Exception {
if (syncTokenService == null) {
syncTokenService = createSyncTokenService();
}
return syncTokenService;
}
private SyncTokenService createSyncTokenService() {
return SyncTokenService.testConstructorAndActivate(getConfig(), getResourceResolverFactory(), getSlingSettingsService());
}
@Override
protected BaseDiscoveryService createDiscoveryService() throws Exception {
return DiscoveryServiceImpl.testConstructor(getResourceResolverFactory(), getAnnouncementRegistry(), getConnectorRegistry(), (ClusterViewServiceImpl) getClusterViewService(), getHeartbeatHandler(), getSlingSettingsService(), getScheduler(), getConfig(), getSyncTokenService());
}
@Override
protected ClusterViewService createClusterViewService() {
return ClusterViewServiceImpl.testConstructor(getSlingSettingsService(), getResourceResolverFactory(), getConfig());
}
private HeartbeatHandler getHeartbeatHandler() throws Exception {
if (viewChecker==null) {
throw new IllegalStateException("heartbeatHandler not yet initialized");
}
return (HeartbeatHandler) getViewChecker();
}
@Override
public Object[] getAdditionalServices(VirtualInstance instance) throws Exception {
if (additionalServices==null) {
additionalServices = createAdditionalServices(instance);
}
return additionalServices;
}
VotingHandler getVotingHandler() throws Exception {
if (votingHandler == null) {
votingHandler = createVotingHandler();
}
return votingHandler;
}
private VotingHandler createVotingHandler() throws Exception {
return VotingHandler.testConstructor(getSlingSettingsService(), getResourceResolverFactory(), getConfig());
}
private Object[] createAdditionalServices(VirtualInstance instance) throws Exception {
Object[] additionals = new Object[1];
additionals[0] = getVotingHandler();
observationListener = new VotingEventListener(instance, votingHandler, getSlingId());
ResourceResolver resourceResolver = getResourceResolverFactory()
.getServiceResourceResolver(null);
Session session = resourceResolver.adaptTo(Session.class);
observationManager = session.getWorkspace()
.getObservationManager();
observationManager.addEventListener(
observationListener
, Event.NODE_ADDED | Event.NODE_REMOVED | Event.NODE_MOVED
| Event.PROPERTY_CHANGED | Event.PROPERTY_ADDED
| Event.PROPERTY_REMOVED | Event.PERSIST, "/", true,
null,
null, false);
return additionals;
}
void stopVoting() {
if (observationListener!=null) {
logger.info("stopVoting: stopping voting of slingId="+getSlingId());
if (observationManager != null) {
logger.info("stop: removing listener for slingId="+getSlingId()+": "+observationListener);
try {
observationManager.removeEventListener(observationListener);
} catch (RepositoryException e) {
logger.error("stopVoting: could not remove listener for slingId="+getSlingId()+": "+observationListener+", "+e, e);
}
}
logger.info("stopVoting: stopping observation listener of slingId="+getSlingId());
observationListener.stop();
observationListener = null;
logger.info("stopVoting: stopped observation listener of slingId="+getSlingId());
} else {
logger.info("stopVoting: observation listener was null for slingId="+getSlingId());
}
}
public FullJR2VirtualInstance fullBuild() throws Exception {
return (FullJR2VirtualInstance) build();
}
@Override
public VirtualInstance build() throws Exception {
if (path==null) {
if (ownRepository) {
setPath("/var/discovery/impl/");
getConfig().setPath("/var/discovery/impl/");
} else {
FullJR2VirtualInstanceBuilder other = (FullJR2VirtualInstanceBuilder) hookedToBuilder;
this.path = other.path;
getConfig().setPath(other.path);
}
}
if (path==null) {
throw new IllegalStateException("no path set");
}
if (!path.startsWith("/")) {
throw new IllegalStateException("path must start with /: "+path);
}
if (!path.endsWith("/")) {
throw new IllegalStateException("path must end with /: "+path);
}
return new FullJR2VirtualInstance(this) {
@Override
public void stop() throws Exception {
if ((observationListener != null) && (observationManager != null)) {
logger.info("stop: removing listener for slingId="+slingId+": "+observationListener);
observationManager.removeEventListener(observationListener);
} else {
logger.warn("stop: could not remove listener for slingId="+slingId+", debugName="+debugName+", observationManager="+observationManager+", observationListener="+observationListener);
}
if (observationListener!=null) {
observationListener.stop();
}
super.stop();
}
@Override
public void assertEstablishedView() {
super.assertEstablishedView();
try {
assertEquals(EstablishedInstanceDescription.class, this
.getClusterViewService().getLocalClusterView().getInstances().get(0)
.getClass());
} catch (UndefinedClusterViewException e) {
fail("Undefined clusterView: "+e);
}
}
};
}
@Override
protected void resetRepo() throws Exception {
logger.info("resetRepo: start, logging in");
Session l = RepositoryProvider.instance().getRepository()
.loginAdministrative(null);
try {
logger.info("resetRepo: removing '/var' ...");
l.removeItem("/var");
logger.info("resetRepo: saving...");
l.save();
logger.info("resetRepo: logging out...");
l.logout();
logger.info("resetRepo: done.");
} catch (Exception e) {
logger.error("resetRepo: Exception while trying to remove /var: "+e, e);
l.refresh(false);
logger.info("resetRepo: logging out after exception");
l.logout();
logger.info("resetRepo: done after exception");
}
}
}