/* * Created on Dec 31, 2004 at the Interface Ecology Lab. */ package ecologylab.serialization.types.scalar; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.regex.Pattern; import ecologylab.appframework.PropertiesAndDirectories; import ecologylab.generic.StringTools; import ecologylab.net.ParsedURL; import ecologylab.serialization.ScalarUnmarshallingContext; import ecologylab.serialization.TranslationContext; import ecologylab.serialization.annotations.simpl_inherit; import ecologylab.serialization.types.CrossLanguageTypeConstants; /** * Type system entry for java.awt.Color. Uses a hex string as initialization. * * @author andruid */ @simpl_inherit public class ParsedURLType extends ReferenceType<ParsedURL> implements CrossLanguageTypeConstants { /** * This constructor should only be called once per session, through * a static initializer, typically in TypeRegistry. * <p> * To get the instance of this type object for use in translations, call * <code>TypeRegistry.get("cm.generic.ParsedURL")</code>. * */ public ParsedURLType() { super(ParsedURL.class, JAVA_PARSED_URL, DOTNET_PARSED_URL, OBJC_PARSED_URL, null); } private static Pattern spaceRegex = Pattern.compile("\\s"); /** * Looks for file in value, and creates a ParsedURL with file set if appropriate. * Otherwise, calls ParsedURL.getAbsolute(). * * @param value String to marshall into a typed instance. * * @see ecologylab.serialization.types.ScalarType#getInstance(java.lang.String, String[], ScalarUnmarshallingContext) */ @Override public ParsedURL getInstance(String value, String[] formatStrings, ScalarUnmarshallingContext scalarUnmarshallingContext) { File file = null; if (value.startsWith("file://")) { int startIndex = 7; value = value.substring(startIndex); try { value = URLDecoder.decode(value, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } file = new File(value); } else if (PropertiesAndDirectories.isWindows()) { if (value.length() > 1 && value.charAt(1) == ':') file = ecologylab.io.Files.newFile(value); else if (value.startsWith("\\\\")) file = new File(value); } if (file != null) { return new ParsedURL(file); } else { boolean hasUnmarshallingContext = scalarUnmarshallingContext != null; if((hasUnmarshallingContext && scalarUnmarshallingContext.fileContext() == null) && spaceRegex.matcher(value).find()) { value = value.replaceAll("\\s","%20"); } //TODO -- do we need to check manually here to see if scalarUnmarshallingContext.fileContext() != null? // or will this resolve a relative file path properly, anyway. // File fileContext = (scalarUnmarshallingContext == null) ? null : scalarUnmarshallingContext.fileContext(); // file = (fileContext == null) ? new File(value) : new File(fileContext, value); // if no colon in first seven characters, must be relative path if (value.lastIndexOf(':', 7) == -1 && hasUnmarshallingContext) { // TODO Auto-generated catch block ParsedURL purlContext = scalarUnmarshallingContext.purlContext(); if (purlContext != null) return purlContext.getRelative(value); } return ParsedURL.getAbsolute(value, "ParsedURLType.getInstance()"); } } public static final String URL_DELIMS = "/&?"; public static final String PRIMARY_URL_DELIM = "/"; public static final Pattern URL_DELIMS_TOKENIZER = Pattern.compile("([" + URL_DELIMS + "]*)([^" + URL_DELIMS + "]+)"); /** * For editing: these are the valid delimiters for separating tokens that make up a field * of this type. * * @return */ @Override public Pattern delimitersTokenizer() { return URL_DELIMS_TOKENIZER; } @Override public String delimeters() { return URL_DELIMS; } @Override public boolean allowNewLines() { return false; } /** * When editing, determines whether delimiters can be included in token strings. * * @return true for URLs */ //FIXME -- Add String delimitersAfter to TextChunk -- interleaved with TextTokens, and //get rid of this!!! @Override public boolean allowDelimitersInTokens() { return true; } /** * When editing, do not allow the user to include these characters in the resulting value String. * @return */ @Override public String illegalChars() { return " !{}\t\n\r"; } /** * When editing, is the field one that should be part of the Term model? * * @return false for URLs */ @Override public boolean composedOfTerms() { return false; } /** * The most basic and fundamental delimiter to use between characters. * * @return The URL implementation, here, returns a slash. */ @Override public String primaryDelimiter() { return PRIMARY_URL_DELIM; } @Override public String marshall(ParsedURL instance, TranslationContext serializationContext) { ParsedURL contextualizedInstance = instance; if (serializationContext != null) { ParsedURL purlContext = serializationContext.purlContext(); if (purlContext != null) { String instanceProtocol = instance.url().getProtocol(); String contextProtocol = purlContext.url().getProtocol(); if (instanceProtocol.equals(contextProtocol)) { int afterProtocolIndex = instanceProtocol.length()+3; String instanceString = instance.toString().substring(afterProtocolIndex); String purlContextString = purlContext.toString().substring(afterProtocolIndex); String pathRelativeTo = StringTools.getPathRelativeTo(instanceString, purlContextString, '/'); if (pathRelativeTo != null) return pathRelativeTo; } } } return super.marshall(contextualizedInstance, serializationContext); } }