| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.sling.installer.provider.jcr.impl; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.regex.Pattern; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** Defines which folders are watched by JcrInstaller, based on |
| * their names. To be accepted, a folder must have a name that |
| * matches the expression, followed by optional suffixes based |
| * on the current RunMode. |
| * |
| * See {@link org.apache.sling.installer.provider.jcr.impl.FolderNameFilterTest} for details. |
| */ |
| class FolderNameFilter { |
| private final Pattern pattern; |
| private final String regexp; |
| private final Set<String> runModes; |
| private final String [] rootPaths; |
| private final Map<String, Integer> rootPriorities = new HashMap<String, Integer>(); |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| /** getPriority computes priorities as follows: each root gets its own base priority, |
| * and paths that match one or several run levels get an additional RUNMODE_PRIORITY_OFFSET |
| * per matched run level |
| */ |
| public static final int RUNMODE_PRIORITY_BOOST = 1; |
| public static final int DEFAULT_ROOT_PRIORITY = 99; |
| |
| FolderNameFilter(final String [] rootsConfig, final String regexp, final Set<String> runModes) { |
| final List<RootPathInfo> rootPathInfos = new ArrayList<RootPathInfo>(); |
| this.regexp = regexp; |
| this.pattern = Pattern.compile(regexp); |
| this.runModes = runModes; |
| |
| // Each entry in rootsConfig is like /libs:100, where 100 |
| // is the priority. |
| // Break that up into paths and priorities |
| this.rootPaths = new String[rootsConfig.length]; |
| for(int i = 0; i < rootsConfig.length; i++) { |
| final String [] parts = rootsConfig[i].split(":"); |
| this.rootPaths[i] = cleanupRootPath(parts[0]); |
| Integer priority = new Integer(DEFAULT_ROOT_PRIORITY); |
| if(parts.length > 1) { |
| try { |
| priority = Integer.parseInt(parts[1].trim()); |
| } catch(NumberFormatException nfe) { |
| log.warn("Invalid priority in path definition '{}'", rootsConfig[i]); |
| } |
| } |
| rootPriorities.put(this.rootPaths[i], priority); |
| rootPathInfos.add(new RootPathInfo(this.rootPaths[i], priority)); |
| log.debug("Root path {} has priority {}", this.rootPaths[i], priority); |
| } |
| // sort root paths by priority |
| Collections.sort(rootPathInfos); |
| int index = 0; |
| for(final RootPathInfo rpi : rootPathInfos) { |
| this.rootPaths[index++] = rpi.path; |
| } |
| } |
| |
| private static final class RootPathInfo implements Comparable<RootPathInfo> { |
| |
| public final String path; |
| private final Integer priority; |
| |
| public RootPathInfo(final String path, final Integer prio) { |
| this.path = path; |
| this.priority = prio; |
| } |
| |
| public int compareTo(RootPathInfo o) { |
| int result = -this.priority.compareTo(o.priority); |
| if ( result == 0 ) { |
| result = this.path.compareTo(o.path); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * Return the list of root paths. |
| * Every entry in the list starts with a slash and the entries are |
| * sorted by priority - highest priority first |
| */ |
| String [] getRootPaths() { |
| return rootPaths; |
| } |
| |
| static String cleanupRootPath(final String str) { |
| String result = str.trim(); |
| if (!result.startsWith("/")) { |
| result = "/" + result; |
| } |
| if (result.endsWith("/")) { |
| result = result.substring(0, result.length() - 1); |
| } |
| return result; |
| } |
| |
| /** If a folder at given path can contain installable resources |
| * (according to our regexp and current RunMode), return the |
| * priority to use for InstallableResource found in that folder. |
| * |
| * @return -1 if path is not an installable folder, else resource priority |
| */ |
| int getPriority(final String path) { |
| int result = 0; |
| List<String> modes = null; |
| boolean match = false; |
| |
| // If path contains dots after the last /, remove suffixes |
| // starting with dots until path matches regexp, and accept |
| // if all suffixes |
| // are included in our list of runmodes |
| final char DOT = '.'; |
| |
| String prefix = path; |
| final int lastSlash = prefix.lastIndexOf('/'); |
| if(lastSlash > 0) { |
| prefix = prefix.substring(lastSlash); |
| } |
| if(prefix.indexOf(DOT) > 0) { |
| int pos = 0; |
| modes = new LinkedList<String>(); |
| while( (pos = prefix.lastIndexOf(DOT)) >= 0) { |
| modes.add(prefix.substring(pos + 1)); |
| prefix = prefix.substring(0, pos); |
| if(pattern.matcher(prefix).matches()) { |
| result = getRootPriority(path); |
| break; |
| } |
| } |
| |
| // If path prefix matches, check that all our runmodes match |
| if(result > 0) { |
| for(String m : modes) { |
| if(runModes.contains(m)) { |
| result += RUNMODE_PRIORITY_BOOST; |
| } else { |
| result = 0; |
| break; |
| } |
| } |
| } |
| |
| } else if(pattern.matcher(path).matches()) { |
| match = true; |
| result = getRootPriority(path); |
| } |
| |
| if(modes != null) { |
| if(log.isDebugEnabled()) { |
| log.debug("getPriority(" + path + ")=" + result + " (prefix=" + prefix + ", run modes=" + modes + ")"); |
| } |
| } else if(match ){ |
| log.debug("getPriority({})={}", path, result); |
| } else { |
| log.debug("getPriority({})={}, path doesn't match regexp", path, result); |
| } |
| |
| return result; |
| } |
| |
| public String toString() { |
| return getClass().getSimpleName() + " (" + regexp + "), RunModes=" + runModes; |
| } |
| |
| int getRootPriority(String path) { |
| for(Map.Entry<String, Integer> e : rootPriorities.entrySet()) { |
| if(path.startsWith(e.getKey())) { |
| return e.getValue().intValue(); |
| } |
| } |
| return 0; |
| } |
| } |