blob: a2856411c17225606acc7b407e80453009eaa69f [file] [log] [blame]
/*
* 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.jackrabbit.oak.plugins.cow;
import org.apache.jackrabbit.oak.api.jmx.CopyOnWriteStoreMBean;
import org.apache.jackrabbit.oak.commons.PropertiesUtil;
import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
import org.apache.jackrabbit.oak.spi.commit.ObserverTracker;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.apache.jackrabbit.oak.spi.state.NodeStoreProvider;
import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardExecutor;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
@Component(
configurationPolicy = ConfigurationPolicy.REQUIRE,
service = {})
public class COWNodeStoreService {
private static final Logger LOG = LoggerFactory.getLogger(COWNodeStoreService.class);
/**
* NodeStoreProvider role
* <br>
* Property indicating that this component will not register as a
* NodeStore but as a NodeStoreProvider with given role
*/
public static final String PROP_ROLE = "role";
private NodeStoreProvider nodeStoreProvider;
private String nodeStoreDescription;
private ComponentContext context;
private ServiceRegistration nsReg;
private Registration mbeanReg;
private ObserverTracker observerTracker;
private Whiteboard whiteboard;
private WhiteboardExecutor executor;
private String role;
@Activate
protected void activate(ComponentContext context, Map<String, ?> config) {
this.role = PropertiesUtil.toString(config.get(PROP_ROLE), null);
this.context = context;
registerNodeStore();
}
@Deactivate
protected void deactivate() {
unregisterNodeStore();
}
private void registerNodeStore() {
if (nsReg != null) {
return;
}
if (nodeStoreProvider == null) {
LOG.info("Waiting for the NodeStoreProvider with role=copy-on-write");
return;
}
if (context == null) {
LOG.info("Waiting for the component activation");
return;
}
COWNodeStore store = new COWNodeStore(nodeStoreProvider.getNodeStore());
whiteboard = new OsgiWhiteboard(context.getBundleContext());
executor = new WhiteboardExecutor();
executor.start(whiteboard);
mbeanReg = registerMBean(whiteboard,
CopyOnWriteStoreMBean.class,
store.new MBeanImpl(),
CopyOnWriteStoreMBean.TYPE,
"Copy-on-write: " + nodeStoreDescription);
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put(Constants.SERVICE_PID, COWNodeStore.class.getName());
props.put("oak.nodestore.description", new String[]{"nodeStoreType=cowStore"});
if (role == null) {
LOG.info("Registering the COW node store");
observerTracker = new ObserverTracker(store);
observerTracker.start(context.getBundleContext());
nsReg = context.getBundleContext().registerService(
new String[]{NodeStore.class.getName()},
store,
props
);
} else {
LOG.info("Registering the COW node store provider");
props.put("role", role);
nsReg = context.getBundleContext().registerService(
new String[]{NodeStoreProvider.class.getName()},
(NodeStoreProvider) () -> store,
props
);
}
}
private void unregisterNodeStore() {
if (mbeanReg != null) {
mbeanReg.unregister();
mbeanReg = null;
}
if (executor != null) {
executor.stop();
executor = null;
}
if (observerTracker != null) {
observerTracker.stop();
observerTracker = null;
}
if (nsReg != null) {
LOG.info("Unregistering the COW node store");
nsReg.unregister();
nsReg = null;
}
}
@Reference(
name = "nodeStoreProvider",
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC,
target = "(role=copy-on-write)")
protected void bindNodeStoreProvider(NodeStoreProvider ns, Map<String, ?> config) {
this.nodeStoreProvider = ns;
this.nodeStoreDescription = PropertiesUtil.toString(config.get("oak.nodestore.description"), ns.getClass().getName());
registerNodeStore();
}
protected void unbindNodeStoreProvider(NodeStoreProvider ns) {
this.nodeStoreProvider = null;
this.nodeStoreDescription = null;
unregisterNodeStore();
}
}