/**
* 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.apereo.portal.io;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apereo.portal.layout.IUserLayoutStore;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
public enum SupportedFileTypes {
LAYOUT("layout", "@username") {
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
boolean rslt = false; // default
boolean isLayout = e.getName().equals(rootElementNodeName);
if (isLayout) {
String username = ((Node) documentNameXPath.evaluate(e)).getText();
rslt = !rdbmdls.isFragmentOwner(username);
}
return rslt;
}
},
FRAGMENT_LAYOUT("layout", "@username", "fragment-layout") {
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
boolean rslt = false; // default
boolean isLayout = e.getName().equals(rootElementNodeName);
if (isLayout) {
String username = ((Node) documentNameXPath.evaluate(e)).getText();
rslt = rdbmdls.isFragmentOwner(username);
}
return rslt;
}
},
PROFILE("profile", "@username") {
// Instance Members
private final XPath profileFNameXPath = fac.createXPath("fname");
@Override
public String getSafeFileNameWithExtension(Element e) {
String namePart = ((Node) documentNameXPath.evaluate(e)).getText();
if (namePart == null) {
String msg =
"The XPath expression '"
+ documentNameXPath.getText()
+ "' didn't match any text in the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
String fNamePart = ((Node) profileFNameXPath.evaluate(e)).getText();
if (fNamePart == null) {
String msg =
"The XPath expression '"
+ profileFNameXPath.getText()
+ "' didn't match any text in the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
StringBuilder rslt = new StringBuilder();
rslt.append(makeSafe(namePart))
.append("-")
.append(makeSafe(fNamePart))
.append(".")
.append(fileExtension);
return rslt.toString();
}
},
PERMISSION("permission", null) {
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
return false;
}
@Override
public String getSafeFileNameWithExtension(Element e) {
throw new UnsupportedOperationException("Not yet supported.");
}
},
PERMISSION_SET("permission-set", null) {
// Instance Members
private final XPath principalXPath = fac.createXPath("principal/*");
private final XPath activityXPath = fac.createXPath("activity");
private final XPath ownerXPath = fac.createXPath("owner");
@Override
public String getSafeFileNameWithExtension(Element e) {
String principalPart = ((Node) principalXPath.evaluate(e)).getText();
if (principalPart == null) {
String msg =
"The XPath expression '"
+ principalXPath.getText()
+ "' didn't match any text in the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
String activityPart = ((Node) activityXPath.evaluate(e)).getText();
if (activityPart == null) {
String msg =
"The XPath expression '"
+ activityXPath.getText()
+ "' didn't match any text in the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
String ownerPart = ((Node) ownerXPath.evaluate(e)).getText();
if (ownerPart == null) {
String msg =
"The XPath expression '"
+ ownerXPath.getText()
+ "' didn't match any text in the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
StringBuilder rslt = new StringBuilder();
rslt.append(makeSafe(principalPart))
.append("__")
.append(makeSafe(activityPart))
.append("__")
.append(makeSafe(ownerPart))
.append(".")
.append(fileExtension);
return rslt.toString();
}
},
MEMBERSHIP("membership", null) {
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
return false;
}
@Override
public String getSafeFileNameWithExtension(Element e) {
throw new UnsupportedOperationException("Not yet supported.");
}
},
CHANNEL("channel-definition", "fname", "channel"),
CHANNEL_TYPE("channel-type", "name"),
GROUP("group", "name") {
private final XPath childrenXPath = fac.createXPath("children");
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
boolean rslt = false; // default
boolean isGroup = e.getName().equals(rootElementNodeName);
if (isGroup) {
Object childrenElement = childrenXPath.evaluate(e);
if (childrenElement != null && childrenElement instanceof List<?>) {
List<?> nodes = (List<?>) childrenElement;
// evaluate() returns an empty list if there are no matches
rslt = nodes.isEmpty();
}
}
return rslt;
}
},
GROUP_MEMBERSHIP("group", "name", "group_membership") {
private final XPath childrenXPath = fac.createXPath("children");
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
boolean rslt = false; // default
boolean isGroup = e.getName().equals(rootElementNodeName);
if (isGroup) {
Object childrenElement = childrenXPath.evaluate(e);
if (childrenElement != null && childrenElement instanceof Node) {
rslt = true;
}
}
return rslt;
}
},
USER("user", "@username") {
private final XPath templateUserXPath = fac.createXPath("default-user");
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
boolean rslt = false; // default
boolean isUser = e.getName().equals(rootElementNodeName);
if (isUser) {
Object defaultUserElement = templateUserXPath.evaluate(e);
if (defaultUserElement != null && defaultUserElement instanceof Node) {
rslt = true;
}
}
return rslt;
}
},
TEMPLATE_USER("user", "@username", "template-user") {
private final XPath templateUserXPath = fac.createXPath("default-user");
@Override
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
boolean rslt = false; // default
boolean isUser = e.getName().equals(rootElementNodeName);
if (isUser) {
Object defaultUserElement = templateUserXPath.evaluate(e);
if (defaultUserElement != null && defaultUserElement instanceof List<?>) {
List<?> nodes = (List<?>) defaultUserElement;
// evaluate() returns an empty list if there are no matches
rslt = nodes.isEmpty();
}
}
return rslt;
}
},
THEME("theme", "name"),
STRUCTURE("structure", "name"),
ENTITY_TYPE("entity-type", "name"),
FRAGMENT_DEFINITION("fragment-definition", "*/@name");
// 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 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);
}
// Instance Members.
protected final String rootElementNodeName;
protected final XPath documentNameXPath;
protected final String fileExtension;
protected final DocumentFactory fac = new DocumentFactory();
/*
* Public API.
*/
public static SupportedFileTypes getApplicableFileType(Element e, IUserLayoutStore rdbmdls) {
// Assertions.
if (e == null) {
String msg = "Argument 'e' [Element] cannot be null";
throw new IllegalArgumentException(msg);
}
if (rdbmdls == null) {
String msg = "Argument 'rdbmdls' [IUserLayoutStore] cannot be null";
throw new IllegalArgumentException(msg);
}
SupportedFileTypes rslt = null;
for (SupportedFileTypes y : SupportedFileTypes.values()) {
if (y.appliesTo(e, rdbmdls)) {
rslt = y;
break;
}
}
if (rslt == null) {
String msg =
"SupportedFileTypes instance not found for the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
return rslt;
}
public String getSafeFileNameWithExtension(Element e) {
String namePart = ((Node) documentNameXPath.evaluate(e)).getText();
if (namePart == null) {
String msg =
"The XPath expression '"
+ documentNameXPath.getText()
+ "' didn't match any text in the specified element: "
+ e.getName();
throw new RuntimeException(msg);
}
return makeSafe(namePart) + "." + fileExtension;
}
/*
* Non-Public Stuff.
*/
SupportedFileTypes(String rootElementNodeName, String documentNameExpression) {
this(rootElementNodeName, documentNameExpression, rootElementNodeName);
}
SupportedFileTypes(
String rootElementNodeName, String documentNameExpression, String fileExtension) {
this.rootElementNodeName = rootElementNodeName;
this.documentNameXPath =
documentNameExpression != null ? fac.createXPath(documentNameExpression) : null;
this.fileExtension = fileExtension;
}
protected boolean appliesTo(Element e, IUserLayoutStore rdbmdls) {
return e.getName().equals(rootElementNodeName);
}
protected final String makeSafe(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;
}
}