001/*
002 *  Copyright 2010 Anyware Services
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
017package org.ametys.web;
018
019import java.util.regex.Pattern;
020
021import javax.jcr.NoSuchWorkspaceException;
022import javax.jcr.RepositoryException;
023import javax.jcr.Session;
024import javax.jcr.observation.Event;
025import javax.jcr.observation.ObservationManager;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029
030import org.ametys.plugins.repository.AmetysObjectResolver;
031import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
032import org.ametys.plugins.repository.activities.ActivityHolder;
033import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
034import org.ametys.runtime.config.Config;
035import org.ametys.web.live.LiveWorkspaceExcludedPathExtensionPoint;
036import org.ametys.web.live.LiveWorkspaceListener;
037import org.ametys.web.repository.site.Site;
038import org.ametys.web.repository.site.SiteManager;
039import org.ametys.web.synchronization.SynchronizeComponent;
040
041/**
042 * Web plugin init class
043 */
044public class Init extends org.ametys.cms.Init
045{
046    private SiteManager _siteManager;
047    private SynchronizeComponent _synchronizeComponent;
048    private LiveWorkspaceExcludedPathExtensionPoint _siteExcludedPathEP;
049    private LiveWorkspaceExcludedPathExtensionPoint _nositeExcludedPathEP;
050    
051    @Override
052    public void service(ServiceManager manager) throws ServiceException
053    {
054        super.service(manager);
055        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
056        _synchronizeComponent = (SynchronizeComponent) manager.lookup(SynchronizeComponent.ROLE);
057        _siteExcludedPathEP = (LiveWorkspaceExcludedPathExtensionPoint) manager.lookup(LiveWorkspaceExcludedPathExtensionPoint.ROLE + ".site");
058        _nositeExcludedPathEP = (LiveWorkspaceExcludedPathExtensionPoint) manager.lookup(LiveWorkspaceExcludedPathExtensionPoint.ROLE + ".nosite");
059    }
060    
061    @Override
062    public void init() throws Exception
063    {
064        DefaultTraversableAmetysObject root = _resolver.resolveByPath("/");
065
066        Session session = _repository.getAdminSession();
067        ObservationManager manager = session.getWorkspace().getObservationManager();
068        
069        // Create Live workspace if needed
070        createLiveWorkspace();
071        
072        // Create archives workspace if needed
073        createArchiveWorkspace();
074        
075        // Register a non-recursive live workspace listener for root nodes
076        manager.addEventListener(new LiveWorkspaceListener(_repository, _synchronizeComponent, getLogger()), 
077                                 Event.NODE_ADDED
078                                 | Event.NODE_REMOVED
079                                 | Event.NODE_MOVED
080                                 | Event.PROPERTY_ADDED
081                                 | Event.PROPERTY_CHANGED
082                                 | Event.PROPERTY_REMOVED, 
083                                 root.getNode().getPath(), false, null, null, false);
084        
085        // Create plugins root node if needed
086        createPluginsRootNode(root);
087        
088        // Create sites root node if needed
089        createSitesRootNode(root);
090        
091        Pattern[] noSiteExcludedPath = _nositeExcludedPathEP.getExcludedPaths();
092        
093        // Register a live workspace listener for plugins, excluding root contents and ACL nodes
094        manager.addEventListener(new LiveWorkspaceListener(_repository, _synchronizeComponent, getLogger(), noSiteExcludedPath), 
095                                 Event.NODE_ADDED
096                                 | Event.NODE_REMOVED
097                                 | Event.NODE_MOVED
098                                 | Event.PROPERTY_ADDED
099                                 | Event.PROPERTY_CHANGED
100                                 | Event.PROPERTY_REMOVED, 
101                                 root.getNode().getPath() + "/ametys:plugins", true, null, null, false);
102        
103        // Create contents root node if needed
104        createContentsRootNode(root);
105        
106        // Create resources root node if needed
107        createResourcesRootNode(root);
108        
109        // Create shared resources (for all sites) root node if needed
110        createSharedResourcesNode(root);
111        
112        root.getNode().getSession().logout();
113        
114        Pattern[] excludedPath = _siteExcludedPathEP.getExcludedPaths();
115        
116        for (Site site : _siteManager.getSites())
117        {
118            // Register a live workspace listener for plugins on each site, excluding root contents
119            manager.addEventListener(new LiveWorkspaceListener(_repository, _synchronizeComponent, getLogger(), excludedPath), 
120                                     Event.NODE_ADDED
121                                     | Event.NODE_REMOVED
122                                     | Event.NODE_MOVED
123                                     | Event.PROPERTY_ADDED
124                                     | Event.PROPERTY_CHANGED
125                                     | Event.PROPERTY_REMOVED, 
126                                     site.getNode().getPath() + "/ametys-internal:plugins", true, null, null, false);
127            
128            // Creates local plugins space at "<site>/ametys-internal:plugins" if needed
129            if (!site.hasChild("ametys-internal:plugins"))
130            {
131                site.createChild("ametys-internal:plugins", "ametys:unstructured");
132            }
133
134            // Register a live workspace listener for resources explorer on each site
135            manager.addEventListener(new LiveWorkspaceListener(_repository, _synchronizeComponent, getLogger()), 
136                                     Event.NODE_ADDED
137                                     | Event.NODE_REMOVED
138                                     | Event.NODE_MOVED
139                                     | Event.PROPERTY_ADDED
140                                     | Event.PROPERTY_CHANGED
141                                     | Event.PROPERTY_REMOVED, 
142                                     site.getNode().getPath() + "/ametys-internal:resources", true, null, null, false);
143            
144            // Creates local resources space at "<site>/ametys-internal:resources" if needed
145            if (!site.hasChild("ametys-internal:resources"))
146            {
147                site.createChild("ametys-internal:resources", "ametys:resources-collection");
148            }
149            
150            // Register a live workspace listener for activities on each site
151            manager.addEventListener(new LiveWorkspaceListener(_repository, _synchronizeComponent, getLogger()), 
152                                     Event.NODE_ADDED
153                                     | Event.NODE_REMOVED
154                                     | Event.NODE_MOVED
155                                     | Event.PROPERTY_ADDED
156                                     | Event.PROPERTY_CHANGED
157                                     | Event.PROPERTY_REMOVED, 
158                                     site.getNode().getPath() + "/" + ActivityHolder.ACTIVITIES_ROOT_NODE_NAME, true, null, null, false);
159            
160            if (site.needsSave())
161            {
162                site.saveChanges();
163            }
164        }
165    }
166    
167    /**
168     * Create the live workspace.
169     * @throws RepositoryException if a repository error occurred.
170     */
171    protected void createLiveWorkspace() throws RepositoryException
172    {
173        Session session = null;
174        Session liveSession = null;
175        
176        try
177        {
178            // Try to login 
179            liveSession = _repository.login(WebConstants.LIVE_WORKSPACE);
180        }
181        catch (NoSuchWorkspaceException e)
182        {
183            getLogger().info("Live workspace does not exist, creating it...");
184            
185            session = _repository.login();
186            session.getWorkspace().createWorkspace(WebConstants.LIVE_WORKSPACE);
187            liveSession = _repository.login(WebConstants.LIVE_WORKSPACE);
188
189            liveSession.getRootNode().addNode(AmetysObjectResolver.ROOT_REPO, AmetysObjectResolver.ROOT_TYPE);
190            liveSession.save();
191        }
192        finally
193        {
194            if (session != null)
195            {
196                session.logout();
197            }
198            if (liveSession != null)
199            {
200                liveSession.logout();
201            }
202        }
203    }
204    
205    /**
206     * Create the JCR root node for sites storage if needed
207     * @param rootNode The JCR root node
208     * @throws RepositoryException Thrown if the node cannot be created
209     */
210    protected void createSitesRootNode(ModifiableTraversableAmetysObject rootNode) throws RepositoryException
211    {
212        if (!rootNode.hasChild(SiteManager.ROOT_SITES))
213        {
214            rootNode.createChild(SiteManager.ROOT_SITES, "ametys:collection");
215            rootNode.saveChanges();
216        }
217    }
218    
219    /**
220     * Create the JCR root node for shared resources storage if needed
221     * @param rootNode The JCR root node
222     * @throws RepositoryException Thrown if the node cannot be created
223     */
224    protected void createSharedResourcesNode(ModifiableTraversableAmetysObject rootNode) throws RepositoryException
225    {
226        // Creates web-explorer space at "/ametys:plugins/web-explorer" if needed
227        DefaultTraversableAmetysObject pluginsNode = (DefaultTraversableAmetysObject) rootNode.getChild("ametys:plugins");
228        if (!pluginsNode.hasChild("web-explorer"))
229        {
230            pluginsNode.createChild("web-explorer", "ametys:unstructured");
231        }
232        
233        if (pluginsNode.needsSave())
234        {
235            pluginsNode.saveChanges();
236        }
237
238        // Creates shared resources space at "/ametys:plugins/web-explorer/shared-resources" if needed
239        boolean useSharedResources = Config.getInstance().getValue("resources.shared.folder");
240        DefaultTraversableAmetysObject explorerNode = (DefaultTraversableAmetysObject) pluginsNode.getChild("web-explorer");
241        
242        if (useSharedResources)
243        {
244            DefaultTraversableAmetysObject sharedRoot;
245            
246            if (!explorerNode.hasChild("shared-resources"))
247            {
248                sharedRoot = (DefaultTraversableAmetysObject) explorerNode.createChild("shared-resources", "ametys:unstructured");
249            }
250            else
251            {
252                sharedRoot = (DefaultTraversableAmetysObject) explorerNode.getChild("shared-resources");
253            }
254            
255            // Also automatically create the "all" share, available to all sites
256            if (!sharedRoot.hasChild("all"))
257            {
258                sharedRoot.createChild("all", "ametys:resources-collection");
259            }
260            
261            if (explorerNode.needsSave())
262            {
263                explorerNode.saveChanges();
264            }
265        }
266    }
267}