001/*
002 * (C) Copyright 2009-2017 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.runtime.datasource;
020
021import java.util.HashMap;
022import java.util.Map;
023
024import javax.naming.NamingException;
025import javax.sql.DataSource;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.runtime.RuntimeServiceException;
030import org.nuxeo.runtime.model.ComponentContext;
031import org.nuxeo.runtime.model.ComponentInstance;
032import org.nuxeo.runtime.model.DefaultComponent;
033
034/**
035 * Nuxeo component allowing the JNDI registration of datasources by extension
036 * point contributions.
037 * <p>
038 * For now only the internal Nuxeo JNDI server is supported.
039 */
040public class DataSourceComponent extends DefaultComponent {
041
042    private final Log log = LogFactory.getLog(DataSourceComponent.class);
043
044    public static final String DATASOURCES_XP = "datasources";
045
046    public static final String ENV_CTX_NAME = "java:comp/env/";
047
048    protected Map<String, DataSourceDescriptor> datasources = new HashMap<>();
049
050    protected Map<String, DataSourceLinkDescriptor> links = new HashMap<>();
051
052    protected final PooledDataSourceRegistry poolRegistry = new PooledDataSourceRegistry();
053
054    protected boolean started;
055
056    @Override
057    public void activate(ComponentContext context) {
058        datasources = new HashMap<>();
059        links = new HashMap<>();
060    }
061
062    @Override
063    public void deactivate(ComponentContext context) {
064        super.deactivate(context);
065        links = null;
066        datasources = null;
067        //TODO should poolRegistry and sorterRegistry be removed?
068    }
069
070    @Override
071    public void registerContribution(Object contrib, String extensionPoint, ComponentInstance component) {
072        if (contrib instanceof DataSourceDescriptor) {
073            addDataSource((DataSourceDescriptor) contrib);
074        } else if (contrib instanceof DataSourceLinkDescriptor) {
075            addDataSourceLink((DataSourceLinkDescriptor) contrib);
076        } else {
077            log.error("Wrong datasource extension type " + contrib.getClass().getName());
078        }
079    }
080
081    @Override
082    public void unregisterContribution(Object contrib, String extensionPoint, ComponentInstance component) {
083        if (contrib instanceof DataSourceDescriptor) {
084            removeDataSource((DataSourceDescriptor) contrib);
085        } else if (contrib instanceof DataSourceLinkDescriptor) {
086            removeDataSourceLink((DataSourceLinkDescriptor) contrib);
087        }
088    }
089
090    @Override
091    public int getApplicationStartedOrder() {
092        return -1000;
093    }
094
095    public boolean isStarted() {
096        return started;
097    }
098
099    @Override
100    public void start(ComponentContext context) {
101        if (started) {
102            return;
103        }
104        started = true;
105        // bind datasources
106        for (DataSourceDescriptor datasourceDesc : datasources.values()) {
107            bindDataSource(datasourceDesc);
108        }
109        // bind links
110        for (DataSourceLinkDescriptor linkDesc : links.values()) {
111            bindDataSourceLink(linkDesc);
112        }
113    }
114
115    @Override
116    public void stop(ComponentContext context) {
117        try {
118            for (DataSourceLinkDescriptor desc : links.values()) {
119                unbindDataSourceLink(desc);
120            }
121            for (DataSourceDescriptor desc : datasources.values()) {
122                unbindDataSource(desc);
123            }
124        } finally {
125            started = false;
126        }
127    }
128
129    protected void addDataSource(DataSourceDescriptor contrib) {
130        datasources.put(contrib.getName(), contrib);
131        bindDataSource(contrib);
132    }
133
134    protected void removeDataSource(DataSourceDescriptor contrib) {
135        unbindDataSource(contrib);
136        datasources.remove(contrib.getName());
137    }
138
139    protected void bindDataSource(DataSourceDescriptor descr) {
140        log.info("Registering datasource: " + descr.getName());
141        poolRegistry.registerPooledDataSource(descr.getName(), descr.getAllProperties());
142    }
143
144    protected void unbindDataSource(DataSourceDescriptor descr) {
145        log.info("Unregistering datasource: " + descr.getName());
146        poolRegistry.unregisterPooledDataSource(descr.getName());
147    }
148
149    protected void addDataSourceLink(DataSourceLinkDescriptor contrib) {
150        links.put(contrib.name, contrib);
151        bindDataSourceLink(contrib);
152    }
153
154    protected void removeDataSourceLink(DataSourceLinkDescriptor contrib) {
155        unbindDataSourceLink(contrib);
156        links.remove(contrib.name);
157    }
158
159    protected void bindDataSourceLink(DataSourceLinkDescriptor descr) {
160        log.info("Registering DataSourceLink: " + descr.name);
161        DataSource ds;
162        try {
163            ds = DataSourceHelper.getDataSource(descr.global, DataSource.class);
164        } catch (NamingException e) {
165            throw new RuntimeServiceException("Cannot find DataSourceLink '" + descr.name + "' in JNDI", e);
166        }
167        poolRegistry.createAlias(DataSourceHelper.relativize(descr.name), ds);
168    }
169
170    protected void unbindDataSourceLink(DataSourceLinkDescriptor descr) {
171        log.info("Unregistering DataSourceLink: " + descr.name);
172        poolRegistry.removeAlias(descr.name);
173    }
174
175    @Override
176    public <T> T getAdapter(Class<T> adapter) {
177        if (adapter.isAssignableFrom(PooledDataSourceRegistry.class)) {
178            return adapter.cast(poolRegistry);
179        }
180        return super.getAdapter(adapter);
181    }
182
183}