001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.configuration2.io; 018 019import java.io.IOException; 020import java.net.URL; 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Set; 025import java.util.regex.Pattern; 026 027/** 028 * A specialized implementation of a {@code FileLocationStrategy} which encapsulates an arbitrary number of 029 * {@code FileLocationStrategy} objects. 030 * <p> 031 * A collection with the wrapped {@code FileLocationStrategy} objects is passed at construction time. During a 032 * [{@code locate()} operation the wrapped strategies are called one after the other until one returns a non <strong>null</strong> 033 * URL. This URL is returned. If none of the wrapped strategies is able to resolve the passed in {@link FileLocator}, 034 * result is <strong>null</strong>. This is similar to the <em>chain of responsibility</em> design pattern. 035 * </p> 036 * <p> 037 * This class, together with the provided concrete {@code FileLocationStrategy} implementations, offers a convenient way 038 * to customize the lookup for configuration files: Just add the desired concrete strategies to a 039 * {@code CombinedLocationStrategy} object. If necessary, custom strategies can be implemented if there are specific 040 * requirements. Note that the order in which strategies are added to a {@code CombinedLocationStrategy} matters: sub 041 * strategies are queried in the same order as they appear in the collection passed to the constructor. 042 * </p> 043 * <p> 044 * See {@link AbstractFileLocationStrategy} learn how to grant an deny URL schemes and hosts. 045 * </p> 046 * 047 * @see AbstractFileLocationStrategy 048 * @since 2.0 049 */ 050public class CombinedLocationStrategy extends AbstractFileLocationStrategy { 051 052 /** 053 * Builds new instances of {@link CombinedLocationStrategy}. 054 * 055 * @since 2.15.0 056 */ 057 public static class Builder extends AbstractBuilder<CombinedLocationStrategy, Builder> { 058 059 /** A collection with all sub strategies managed by this object. */ 060 private Collection<? extends FileLocationStrategy> subStrategies; 061 062 /** 063 * Constructs a new instance. 064 */ 065 public Builder() { 066 // empty 067 } 068 069 @Override 070 public CombinedLocationStrategy get() throws IOException { 071 return new CombinedLocationStrategy(this); 072 } 073 074 /** 075 * Propagates properties of the parent builder scheme and host to subStrategies. 076 * 077 * @return {@code this} instance. 078 */ 079 public Builder propagate() { 080 if (subStrategies != null) { 081 subStrategies.forEach(e -> { 082 if (e instanceof AbstractFileLocationStrategy) { 083 final AbstractFileLocationStrategy afls = (AbstractFileLocationStrategy) e; 084 final Set<String> schemes = afls.getSchemes(); 085 schemes.clear(); 086 schemes.addAll(getSchemes()); 087 final Set<Pattern> hosts = afls.getHosts(); 088 hosts.clear(); 089 hosts.addAll(getHosts()); 090 } 091 }); 092 } 093 return asThis(); 094 } 095 096 /** 097 * Sets the collection with sub strategies. 098 * 099 * @param subStrategies the collection with sub strategies. 100 * @return {@code this} instance. 101 */ 102 public Builder setSubStrategies(final Collection<FileLocationStrategy> subStrategies) { 103 this.subStrategies = subStrategies; 104 return asThis(); 105 } 106 107 } 108 109 /** A collection with all sub strategies managed by this object. */ 110 private final Collection<FileLocationStrategy> subStrategies; 111 112 /** 113 * Constructs a new instance. 114 * 115 * @param builder How to build the instance. 116 */ 117 private CombinedLocationStrategy(final Builder builder) { 118 super(builder); 119 if (builder.subStrategies == null) { 120 throw new IllegalArgumentException("Collection with sub strategies must not be null."); 121 } 122 if (builder.subStrategies.contains(null)) { 123 throw new IllegalArgumentException("Collection with sub strategies contains null entry."); 124 } 125 subStrategies = Collections.unmodifiableCollection(new ArrayList<>(builder.subStrategies)); 126 } 127 128 /** 129 * Creates a new instance of {@code CombinedLocationStrategy} and initializes it with the provided sub strategies. The 130 * passed in collection must not be <strong>null</strong> or contain <strong>null</strong> elements. 131 * 132 * @param subs the collection with sub strategies. 133 * @throws IllegalArgumentException if the collection is <strong>null</strong> or has <strong>null</strong> elements. 134 */ 135 public CombinedLocationStrategy(final Collection<FileLocationStrategy> subs) { 136 this(new Builder().setSubStrategies(subs)); 137 } 138 139 /** 140 * Gets a (unmodifiable) collection with the sub strategies managed by this object. 141 * 142 * @return the sub {@code FileLocationStrategy} objects 143 */ 144 public Collection<FileLocationStrategy> getSubStrategies() { 145 return subStrategies; 146 } 147 148 /** 149 * {@inheritDoc} This implementation tries to locate the file by delegating to the managed sub strategies. 150 */ 151 @Override 152 public URL locate(final FileSystem fileSystem, final FileLocator locator) { 153 for (final FileLocationStrategy sub : getSubStrategies()) { 154 final URL url = sub.locate(fileSystem, locator); 155 if (url != null) { 156 return check(url); 157 } 158 } 159 return null; 160 } 161}