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.cms.source; 017 018import java.io.IOException; 019import java.net.MalformedURLException; 020import java.util.Map; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024import org.apache.avalon.framework.context.Context; 025import org.apache.avalon.framework.context.ContextException; 026import org.apache.avalon.framework.context.Contextualizable; 027import org.apache.avalon.framework.logger.AbstractLogEnabled; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.cocoon.components.ContextHelper; 032import org.apache.cocoon.environment.Request; 033import org.apache.excalibur.source.Source; 034import org.apache.excalibur.source.SourceFactory; 035 036/** 037 * This factory looks for files in the current skin and fallback in the current plugin dir. 038 * Use: content-view:[view]://path_to_file 039 * Will first look in the skin of the current site in the sub-directory stylesheet/{contenttype} => skins/{skin}/stylesheets/{contenttype}/path_to_file 040 * And if the file does not exist will search in plugin:{currentPluginName}://path_to_file 041 */ 042public class ContentViewSourceFactory extends AbstractLogEnabled implements SourceFactory, Contextualizable, Serviceable 043{ 044 // regexp for location : content-view://<ctype>/<view>/<format>.<extension> 045 private static final Pattern __SOURCE_PATTERN = Pattern.compile("^[^:]*+://([^/]+)/view-([^/]*)/([^/]+)\\.([^/]+)$"); 046 047 private Context _context; 048 private ContentView _contentView; 049 private ServiceManager _manager; 050 051 public void service(ServiceManager manager) throws ServiceException 052 { 053 _manager = manager; 054 } 055 056 @Override 057 public void contextualize(Context context) throws ContextException 058 { 059 _context = context; 060 } 061 062 @Override 063 public Source getSource(String location, Map parameters) throws IOException, MalformedURLException 064 { 065 // lazy initialization to prevent chicken/egg scenario on startup 066 if (_contentView == null) 067 { 068 try 069 { 070 _contentView = (ContentView) _manager.lookup(ContentView.ROLE); 071 } 072 catch (ServiceException e) 073 { 074 throw new IllegalStateException("Exception while getting ContentView", e); 075 } 076 } 077 078 Matcher m = __SOURCE_PATTERN.matcher(location); 079 if (!m.matches()) 080 { 081 throw new MalformedURLException("URI must be like protocol://<ctype>/view-<view>/<format>.<extension>. Location was '" + location + "'"); 082 } 083 084 Request request = ContextHelper.getRequest(_context); 085 String pluginName = request.getParameter("pluginName"); 086 if (pluginName == null) 087 { 088 pluginName = (String) request.getAttribute("pluginName"); 089 } 090 091 String contentType = m.group(1); 092 String view = m.group(2); 093 String format = m.group(3); 094 String extension = m.group(4); 095 096 if (view == null || "".equals(view)) 097 { 098 view = "main"; 099 } 100 101 return _contentView.getSource(location, contentType, view, format, pluginName, extension); 102 } 103 104 @Override 105 public void release(Source source) 106 { 107 // empty method 108 } 109}