001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (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.ecm.core.api.pathsegment;
020
021import java.util.LinkedList;
022
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.nuxeo.ecm.core.api.DocumentModel;
026import org.nuxeo.ecm.core.api.NuxeoException;
027import org.nuxeo.runtime.model.ComponentContext;
028import org.nuxeo.runtime.model.ComponentInstance;
029import org.nuxeo.runtime.model.DefaultComponent;
030
031/**
032 * Central service for the generation of a path segment for a document.
033 */
034public class PathSegmentComponent extends DefaultComponent implements PathSegmentService {
035
036    private static final Log log = LogFactory.getLog(PathSegmentComponent.class);
037
038    public static final String XP = "pathSegmentService";
039
040    protected LinkedList<Class<? extends PathSegmentService>> contribs;
041
042    protected PathSegmentService service;
043
044    protected boolean recompute;
045
046    @Override
047    public void activate(ComponentContext context) {
048        contribs = new LinkedList<Class<? extends PathSegmentService>>();
049        recompute = true;
050        service = null;
051    }
052
053    @Override
054    public void deactivate(ComponentContext context) {
055        contribs.clear();
056        service = null;
057    }
058
059    @Override
060    @SuppressWarnings("unchecked")
061    public void registerContribution(Object contrib, String xp, ComponentInstance contributor) {
062        if (!XP.equals(xp)) {
063            log.error("Unknown extension point " + xp);
064            return;
065        }
066        if (!(contrib instanceof PathSegmentServiceDescriptor)) {
067            log.error("Invalid contribution: " + contrib.getClass().getName());
068            return;
069        }
070        PathSegmentServiceDescriptor desc = (PathSegmentServiceDescriptor) contrib;
071        Class<?> klass;
072        try {
073            klass = Class.forName(desc.className);
074        } catch (ClassNotFoundException e) {
075            log.error("Invalid contribution class: " + desc.className);
076            return;
077        }
078        if (!PathSegmentService.class.isAssignableFrom(klass)) {
079            log.error("Invalid contribution class: " + desc.className);
080            return;
081        }
082        contribs.add((Class<PathSegmentService>) klass);
083        log.info("Registered path segment service: " + desc.className);
084        recompute = true;
085    }
086
087    @Override
088    public void unregisterContribution(Object contrib, String xp, ComponentInstance contributor) {
089        if (!XP.equals(xp)) {
090            return;
091        }
092        if (!(contrib instanceof PathSegmentServiceDescriptor)) {
093            return;
094        }
095        PathSegmentServiceDescriptor desc = (PathSegmentServiceDescriptor) contrib;
096        Class<?> klass;
097        try {
098            klass = Class.forName(desc.className);
099        } catch (ClassNotFoundException e) {
100            return;
101        }
102        if (!klass.isAssignableFrom(PathSegmentService.class)) {
103            return;
104        }
105        contribs.remove(klass);
106        log.info("Unregistered path segment service: " + desc.className);
107        recompute = true;
108    }
109
110    @Override
111    public String generatePathSegment(DocumentModel doc) {
112        if (recompute) {
113            recompute();
114            recompute = false;
115        }
116        return service.generatePathSegment(doc);
117    }
118
119    protected void recompute() {
120        Class<? extends PathSegmentService> klass;
121        if (contribs.isEmpty()) {
122            klass = PathSegmentServiceDefault.class;
123        } else {
124            klass = contribs.getLast();
125        }
126        if (service == null || klass != service.getClass()) {
127            try {
128                service = klass.newInstance();
129            } catch (ReflectiveOperationException e) {
130                throw new NuxeoException(e);
131            }
132        } // else keep old service instance
133    }
134
135    @Override
136    public String generatePathSegment(String s) {
137        if (recompute) {
138            recompute();
139            recompute = false;
140        }
141        return service.generatePathSegment(s);
142    }
143
144    @Override
145    public int getMaxSize() {
146        if (recompute) {
147            recompute();
148            recompute = false;
149        }
150        return service.getMaxSize();
151    }
152}