001/* 002 * Copyright 2012 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.core.cocoon.source; 017 018import java.io.IOException; 019import java.net.MalformedURLException; 020import java.util.ArrayList; 021import java.util.List; 022import java.util.Map; 023import java.util.regex.Matcher; 024import java.util.regex.Pattern; 025 026import org.apache.avalon.framework.configuration.Configurable; 027import org.apache.avalon.framework.configuration.Configuration; 028import org.apache.avalon.framework.configuration.ConfigurationException; 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.commons.lang.StringUtils; 035import org.apache.excalibur.source.Source; 036import org.apache.excalibur.source.SourceFactory; 037import org.apache.excalibur.source.SourceNotFoundException; 038import org.apache.excalibur.source.SourceResolver; 039 040/** 041 * Factory for reading files in one protocol and switch to others if not found. 042 * Configuration should be like:<br><pre><code> 043 * <match>kernel://(.*)</match> 044 * <protocols> 045 * <protocol>resource://org/ametys/runtime/kernel/{1}</protocol> 046 * <protocol>context://kernel/{1}</protocol> 047 * </protocols></code></pre> 048 */ 049public class ProxySourceFactory extends AbstractLogEnabled implements SourceFactory, ThreadSafe, Serviceable, Configurable 050{ 051 /** URI matcher */ 052 protected Pattern _matcher; 053 054 /** Proxied sources */ 055 protected List<String> _protocols; 056 057 private SourceResolver _sourceResolver; 058 private ServiceManager _manager; 059 060 @Override 061 public void configure(Configuration configuration) throws ConfigurationException 062 { 063 _matcher = Pattern.compile(configuration.getChild("match").getValue()); 064 065 _protocols = new ArrayList<>(); 066 for (Configuration protocolConf : configuration.getChild("protocols").getChildren("protocol")) 067 { 068 String protocol = protocolConf.getValue(); 069 if (!StringUtils.isBlank(protocol)) 070 { 071 _protocols.add(protocol); 072 } 073 else 074 { 075 getLogger().warn("Trying to configure a blank protocol. Ignoring this line."); 076 } 077 } 078 079 if (_protocols.size() == 0) 080 { 081 throw new ConfigurationException("Cannot configure this protocol with no redirecting protocols. Add <protocol>...</protocol> items in this component configuration.", configuration); 082 } 083 } 084 085 @Override 086 public void service(ServiceManager manager) throws ServiceException 087 { 088 _manager = manager; 089 } 090 091 @Override 092 public Source getSource(String location, Map parameters) throws IOException, MalformedURLException 093 { 094 if (_sourceResolver == null) 095 { 096 try 097 { 098 _sourceResolver = (SourceResolver) _manager.lookup(SourceResolver.ROLE); 099 } 100 catch (ServiceException e) 101 { 102 throw new IOException(e); 103 } 104 } 105 106 Matcher matcher = _matcher.matcher(location); 107 if (!matcher.matches()) 108 { 109 throw new MalformedURLException("Invalid format for source : " + location); 110 } 111 112 Source source = null; 113 for (String protocol : _protocols) 114 { 115 String uri = protocol; 116 try 117 { 118 for (int groupIndex = 0; groupIndex <= matcher.groupCount(); groupIndex++) 119 { 120 uri = uri.replaceAll("\\{" + groupIndex + "\\}", matcher.group(groupIndex)); 121 } 122 123 source = _sourceResolver.resolveURI(uri, null, parameters); 124 if (!source.exists()) 125 { 126 _sourceResolver.release(source); 127 source = null; 128 } 129 else 130 { 131 return source; 132 } 133 } 134 catch (IOException e) 135 { 136 // nothing to do... 137 } 138 } 139 140 throw new SourceNotFoundException("Source not found '" + location + "'. (tried successively in " + _protocols + ")"); 141 } 142 143 @Override 144 public void release(Source source) 145 { 146 // Should never be called 147 } 148}