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 */ 016package org.ametys.web.skin; 017 018import java.io.File; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.CascadingRuntimeException; 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.context.Context; 027import org.apache.avalon.framework.context.ContextException; 028import org.apache.avalon.framework.context.Contextualizable; 029import org.apache.avalon.framework.logger.AbstractLogEnabled; 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.Serviceable; 033import org.apache.avalon.framework.thread.ThreadSafe; 034import org.apache.cocoon.Constants; 035import org.apache.cocoon.components.ContextHelper; 036import org.apache.cocoon.environment.Request; 037import org.apache.commons.io.FileUtils; 038import org.apache.commons.lang.StringUtils; 039import org.apache.excalibur.source.SourceResolver; 040 041import org.ametys.runtime.servlet.RuntimeConfig; 042import org.ametys.web.repository.site.SiteManager; 043 044/** 045 * Manages the templates 046 */ 047public class SkinsManager extends AbstractLogEnabled implements ThreadSafe, Serviceable, Component, Contextualizable 048{ 049 /** The avalon role name */ 050 public static final String ROLE = SkinsManager.class.getName(); 051 052 /** The set of templates classified by skins */ 053 protected Map<String, Skin> _skins = new HashMap<>(); 054 055 /** The avalon service manager */ 056 protected ServiceManager _manager; 057 /** The excalibur source resolver */ 058 protected SourceResolver _sourceResolver; 059 /** Avalon context */ 060 protected Context _context; 061 /** Cocoon context */ 062 protected org.apache.cocoon.environment.Context _cocoonContext; 063 /** The site manager */ 064 protected SiteManager _siteManager; 065 066 @Override 067 public void service(ServiceManager manager) throws ServiceException 068 { 069 _manager = manager; 070 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 071 } 072 073 @Override 074 public void contextualize(Context context) throws ContextException 075 { 076 _context = context; 077 _cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT); 078 } 079 080 /** 081 * Get the list of existing skins 082 * @return A set of skin names. Can be null if there is an error. 083 */ 084 public Set<String> getSkins() 085 { 086 try 087 { 088 Set<String> skins = new HashSet<>(); 089 090 File skinsDir = new File(getSkinsLocation()); 091 if (skinsDir.exists() && skinsDir.isDirectory()) 092 { 093 for (File child : skinsDir.listFiles()) 094 { 095 if (_skinExists(child)) 096 { 097 skins.add(child.getName()); 098 } 099 } 100 } 101 102 return skins; 103 } 104 catch (Exception e) 105 { 106 getLogger().error("Can not determine the list of skins available", e); 107 return null; 108 } 109 } 110 111 /** 112 * Get a skin 113 * @param id The id of the skin 114 * @return The skin or null if the skin does not exist 115 */ 116 @SuppressWarnings("null") 117 public Skin getSkin(String id) 118 { 119 try 120 { 121 File skinsDir = new File (_getSkinLocation(id)); 122 123 boolean skinDirExists = _skinExists(skinsDir); 124 Skin skin = _skins.get(skinsDir.getAbsolutePath()); 125 if (skin == null && skinDirExists) 126 { 127 skin = new Skin(id, new File (_getSkinLocation(id))); 128 _skins.put(skinsDir.getAbsolutePath(), skin); 129 } 130 else if (!skinDirExists) 131 { 132 _skins.put(skinsDir.getAbsolutePath(), null); 133 return null; 134 } 135 136 skin.refreshValues(); 137 return skin; 138 } 139 catch (Exception e) 140 { 141 throw new IllegalStateException("Can not create the skin DAO for skin '" + id + "'", e); 142 } 143 } 144 145 /** 146 * Get the skins location 147 * @return the skin location 148 */ 149 public String getSkinsLocation () 150 { 151 try 152 { 153 Request request = ContextHelper.getRequest(_context); 154 String skinLocation = (String) request.getAttribute("skin-location"); 155 if (skinLocation != null) 156 { 157 return new File(RuntimeConfig.getInstance().getAmetysHome(), skinLocation).getPath(); 158 } 159 } 160 catch (CascadingRuntimeException e) 161 { 162 // Ignore 163 } 164 165 return _cocoonContext.getRealPath("/skins"); 166 } 167 168 /** 169 * Get the skin name from request or <code>null</code> if not found 170 * @param request The request 171 * @return The skin name or <code>null</code> 172 */ 173 public String getSkinNameFromRequest (Request request) 174 { 175 if (_siteManager == null) 176 { 177 try 178 { 179 _siteManager = (SiteManager) _manager.lookup(SiteManager.ROLE); 180 } 181 catch (ServiceException e) 182 { 183 throw new IllegalStateException(e); 184 } 185 } 186 187 // First, search the skin name in the request attributes. 188 String skinName = (String) request.getAttribute("skin"); 189 190 // Then, test if the site name is present as a request attribute to deduce the skin name. 191 if (StringUtils.isEmpty(skinName)) 192 { 193 String siteName = (String) request.getAttribute("site"); 194 if (StringUtils.isEmpty(siteName)) 195 { 196 siteName = (String) request.getAttribute("siteName"); 197 } 198 199 if (StringUtils.isNotEmpty(siteName)) 200 { 201 skinName = _siteManager.getSite(siteName).getSkinId(); 202 } 203 } 204 205 return skinName; 206 } 207 208 /** 209 * Get the skin location 210 * @param id The id of the skin 211 * @return the skin location 212 */ 213 private String _getSkinLocation (String id) 214 { 215 Request request = ContextHelper.getRequest(_context); 216 String skinLocation = (String) request.getAttribute("skin-location"); 217 if (skinLocation != null) 218 { 219 return FileUtils.getFile(RuntimeConfig.getInstance().getAmetysHome(), skinLocation, id).getPath(); 220 } 221 222 return _cocoonContext.getRealPath("/skins/" + id); 223 } 224 225 private boolean _skinExists(File skinsDir) 226 { 227 if (!skinsDir.exists() || !skinsDir.isDirectory()) 228 { 229 return false; 230 } 231 232 File templatesDir = new File(skinsDir, "templates"); 233 if (!templatesDir.exists() || !templatesDir.isDirectory()) 234 { 235 return false; 236 } 237 238 return true; 239 } 240}