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 * http://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.wicket.util.resource; 018 019import java.util.Arrays; 020import java.util.HashSet; 021import java.util.Locale; 022import java.util.Set; 023import java.util.regex.Matcher; 024import java.util.regex.Pattern; 025 026import org.apache.wicket.util.string.Strings; 027 028/** 029 * 030 * @author Juergen Donnerstag 031 */ 032public class ResourceUtils 033{ 034 /** The default postfix for minified names (ex: /css/mystyle.min.css) **/ 035 public static final String MIN_POSTFIX_DEFAULT = "min"; 036 /** The default postfix for minified names (ex: /css/mystyle.min.css) **/ 037 public static final String MIN_POSTFIX_DEFAULT_AS_EXTENSION = ".min."; 038 /** Regular expression patter to extract the locale from the filename (ex: de_DE) **/ 039 private static final Pattern LOCALE_MIN_PATTERN = Pattern 040 .compile("_([a-z]{2})(_([A-Z]{2})(_([^_\\.]+))?)?(\\.min)?$"); 041 /** Stores standard ISO country codes from {@code java.util.Locale} **/ 042 private final static Set<String> isoCountries = new HashSet<>( 043 Arrays.asList(Locale.getISOCountries())); 044 /** Stores standard ISO language codes from {@code java.util.Locale} **/ 045 private final static Set<String> isoLanguages = new HashSet<>( 046 Arrays.asList(Locale.getISOLanguages())); 047 048 /** 049 * Return the minified version for a given resource name. 050 * For example '/css/coolTheme.css' becomes '/css/coolTheme.min.css' 051 * 052 * @param name 053 * The original resource name 054 * @param minPostfix 055 * The postfix to use for minified name 056 * @return The minified resource name 057 */ 058 public static String getMinifiedName(String name, String minPostfix) 059 { 060 String minifiedName; 061 int idxOfExtension = name.lastIndexOf('.'); 062 final String dottedPostfix = "." + minPostfix; 063 064 if (idxOfExtension > -1) 065 { 066 String extension = name.substring(idxOfExtension); 067 final String baseName = name.substring(0, name.length() - extension.length() + 1); 068 if (!dottedPostfix.equals(extension) && !baseName.endsWith(dottedPostfix + ".")) 069 { 070 minifiedName = baseName + minPostfix + extension; 071 } else 072 { 073 minifiedName = name; 074 } 075 } else 076 { 077 minifiedName = name + dottedPostfix; 078 } 079 return minifiedName; 080 } 081 082 /** 083 * Extract the locale from the filename taking into account possible minimized resource name. 084 * 085 * E.g. {@code file_us_EN.min.js} will correctly determine a locale of {@code us_EN} by 086 * stripping the {@code .min} from the filename, the filename returned will be 087 * {@code file.min.js}, if you want the {@code .min} to be removed as well, use 088 * {@link #getLocaleFromFilename(String)} instead. 089 * 090 * @param path 091 * The file path 092 * @return The updated path, without the locale 093 */ 094 public static PathLocale getLocaleFromFilename(String path) 095 { 096 String extension = ""; 097 098 final int pos = path.lastIndexOf('.'); 099 if (pos != -1) 100 { 101 extension = path.substring(pos); 102 path = path.substring(0, pos); 103 } 104 105 String filename = Strings.lastPathComponent(path, '/'); 106 Matcher matcher = LOCALE_MIN_PATTERN.matcher(filename); 107 if (matcher.find()) 108 { 109 String language = matcher.group(1); 110 String country = matcher.group(3); 111 String variant = matcher.group(5); 112 String min = matcher.group(6); 113 114 // did we find a language? 115 if (language != null) 116 { 117 if (isoLanguages.contains(language) == false) 118 { 119 language = null; 120 country = null; 121 variant = null; 122 } 123 } 124 125 // did we find a country? 126 if ((language != null) && (country != null)) 127 { 128 if (isoCountries.contains(country) == false) 129 { 130 country = null; 131 variant = null; 132 } 133 } 134 135 if (language != null) 136 { 137 int languagePos = path.length() - filename.length() + matcher.start(); 138 String basePath = path.substring(0, languagePos) + (min == null ? "" : min) + 139 extension; 140 141 Locale locale = new Locale(language, country != null ? country : "", 142 variant != null ? variant : ""); 143 144 return new PathLocale(basePath, locale); 145 } 146 } // else skip the whole thing... probably user specific underscores used 147 148 return new PathLocale(path + extension, null); 149 } 150 151 /** 152 * 153 */ 154 public static class PathLocale 155 { 156 /** */ 157 public final String path; 158 159 /** */ 160 public final Locale locale; 161 162 /** 163 * @param path 164 * @param locale 165 */ 166 public PathLocale(final String path, final Locale locale) 167 { 168 this.path = path; 169 this.locale = locale; 170 } 171 } 172}