/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.jasig.portlet.calendar.io;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.danann.cernunnos.EntityConfig;
import org.danann.cernunnos.Formula;
import org.danann.cernunnos.Phrase;
import org.danann.cernunnos.Reagent;
import org.danann.cernunnos.ReagentType;
import org.danann.cernunnos.SimpleFormula;
import org.danann.cernunnos.SimpleReagent;
import org.danann.cernunnos.TaskRequest;
import org.danann.cernunnos.TaskResponse;
/**
* @author Eric Dalquist
* @version $Revision$
*/
public class SafeFileNamePhrase implements Phrase {
// Reserved names on Windows (see http://en.wikipedia.org/wiki/Filename)
private static final Pattern[] WINDOWS_INVALID_PATTERNS =
new Pattern[] {
Pattern.compile("AUX"),
Pattern.compile("CLOCK\\$"),
Pattern.compile("COM\\d*"),
Pattern.compile("CON"),
Pattern.compile("LPT\\d*"),
Pattern.compile("NUL"),
Pattern.compile("PRN")
};
private static final Map<Pattern, String> REPLACEMENT_PAIRS;
static {
final Map<Pattern, String> pairs = new LinkedHashMap<Pattern, String>();
pairs.put(Pattern.compile("/|\\\\"), ".");
pairs.put(Pattern.compile("[~`@\\|\\s#$\\*]"), "_");
REPLACEMENT_PAIRS = Collections.unmodifiableMap(pairs);
}
public static final Reagent HUMAN_FILE_NAME =
new SimpleReagent(
"HUMAN_FILE_NAME",
"descendant-or-self::text()",
ReagentType.PHRASE,
String.class,
"Human readable version of the file name to make safe");
// Instance Members.
private Phrase humanFileNamePhrase;
/* (non-Javadoc)
* @see org.danann.cernunnos.Bootstrappable#init(org.danann.cernunnos.EntityConfig)
*/
public void init(EntityConfig config) {
this.humanFileNamePhrase = (Phrase) config.getValue(HUMAN_FILE_NAME);
}
/* (non-Javadoc)
* @see org.danann.cernunnos.Bootstrappable#getFormula()
*/
public Formula getFormula() {
return new SimpleFormula(SafeFileNamePhrase.class, new Reagent[] {HUMAN_FILE_NAME});
}
/* (non-Javadoc)
* @see org.danann.cernunnos.Phrase#evaluate(org.danann.cernunnos.TaskRequest, org.danann.cernunnos.TaskResponse)
*/
public Object evaluate(TaskRequest req, TaskResponse res) {
final String humanFileName = (String) this.humanFileNamePhrase.evaluate(req, res);
return this.getSafeFileName(humanFileName);
}
protected String getSafeFileName(String name) {
//Replace invalid characters
for (final Map.Entry<Pattern, String> pair : REPLACEMENT_PAIRS.entrySet()) {
final Pattern pattern = pair.getKey();
final Matcher matcher = pattern.matcher(name);
name = matcher.replaceAll(pair.getValue());
}
// Make sure the name doesn't violate a Windows reserved word...
final String upperCaseName = name.toUpperCase();
for (Pattern pattern : WINDOWS_INVALID_PATTERNS) {
if (pattern.matcher(upperCaseName).matches()) {
name = "uP-" + name;
break;
}
}
return name;
}
}