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