001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 *
012 * $Id$
013 */
014
015package org.nuxeo.runtime.deploy;
016
017import java.io.File;
018import java.io.IOException;
019import java.net.URI;
020import java.net.URISyntaxException;
021import java.net.URL;
022import java.util.HashMap;
023import java.util.Map;
024
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027import org.nuxeo.common.collections.ListenerList;
028import org.nuxeo.runtime.model.RuntimeContext;
029
030/**
031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
032 */
033public class ConfigurationDeployer implements FileChangeListener {
034
035    private static final Log log = LogFactory.getLog(ConfigurationDeployer.class);
036
037    protected final Map<String, Entry> urls;
038
039    protected final FileChangeNotifier notifier;
040
041    protected final ListenerList listeners = new ListenerList();
042
043    public ConfigurationDeployer() {
044        this(null);
045    }
046
047    public ConfigurationDeployer(FileChangeNotifier notifier) {
048        this.notifier = notifier;
049        urls = new HashMap<String, Entry>();
050        if (notifier != null) {
051            notifier.addListener(this);
052        }
053    }
054
055    public void deploy(RuntimeContext ctx, URL url, boolean trackChanges) throws IOException {
056        File watchFile = null;
057        if (trackChanges) {
058            try {
059                String str = url.toExternalForm();
060                if (str.startsWith("file:")) {
061                    watchFile = new File(url.toURI());
062                } else if (str.startsWith("jar:file:")) {
063                    int p = str.lastIndexOf('!');
064                    if (p > -1) {
065                        str = str.substring(4, p);
066                    } else {
067                        str = str.substring(4);
068                    }
069                    watchFile = new File(new URI(str));
070                }
071            } catch (URISyntaxException e) {
072                log.error(e);
073                watchFile = null;
074            }
075        }
076        _deploy(ctx, url, watchFile, trackChanges);
077    }
078
079    public void undeploy(URL url) throws IOException {
080        Entry entry = urls.remove(url.toExternalForm());
081        if (entry != null) {
082            _undeploy(entry);
083        }
084    }
085
086    public synchronized void _undeploy(Entry entry) throws IOException {
087        try {
088            entry.ctx.undeploy(entry.url);
089        } finally {
090            if (notifier != null && entry.watchFile != null) {
091                notifier.unwatch(entry.url.toExternalForm(), entry.watchFile);
092            }
093        }
094    }
095
096    public void deploy(RuntimeContext ctx, File file, boolean trackChanges) throws IOException {
097        _deploy(ctx, file.getCanonicalFile().toURI().toURL(), file, trackChanges);
098    }
099
100    public void undeploy(File file) throws IOException {
101        undeploy(file.getCanonicalFile().toURI().toURL());
102    }
103
104    protected synchronized void _deploy(RuntimeContext ctx, URL url, File watchFile, boolean trackChanges)
105            throws IOException {
106        String id = url.toExternalForm();
107        Entry entry = new Entry(ctx, url, watchFile);
108        ctx.deploy(url);
109        urls.put(id, entry);
110        if (trackChanges && notifier != null && watchFile != null) {
111            notifier.watch(id, watchFile);
112        }
113    }
114
115    @Override
116    public void fileChanged(FileChangeNotifier.FileEntry entry, long now) {
117        Entry e = urls.get(entry.id);
118        if (e != null) {
119            try {
120                e.ctx.undeploy(e.url);
121                e.ctx.deploy(e.url);
122            } catch (IOException ex) {
123                throw new RuntimeException(ex);
124            } finally {
125                fireConfigurationChanged(e);
126            }
127        }
128    }
129
130    public void addConfigurationChangedListener(ConfigurationChangedListener listener) {
131        listeners.add(listener);
132    }
133
134    public void removeConfigurationChangedListener(ConfigurationChangedListener listener) {
135        listeners.remove(listener);
136    }
137
138    public void fireConfigurationChanged(Entry entry) {
139        for (Object obj : listeners.getListenersCopy()) {
140            ((ConfigurationChangedListener) obj).configurationChanged(entry);
141        }
142    }
143
144    public static class Entry {
145        final RuntimeContext ctx;
146
147        final URL url;
148
149        File watchFile;
150
151        Entry(RuntimeContext ctx, URL config, File watchFile) throws IOException {
152            url = config;
153            this.ctx = ctx;
154            if (watchFile != null) {
155                this.watchFile = watchFile.getCanonicalFile();
156            }
157        }
158
159        public RuntimeContext getContext() {
160            return ctx;
161        }
162
163        public File getWatchFile() {
164            return watchFile;
165        }
166
167        public URL getUrl() {
168            return url;
169        }
170
171        @Override
172        public String toString() {
173            return url.toExternalForm();
174        }
175    }
176
177}