http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIFactoryImpl.java
----------------------------------------------------------------------
diff --git 
a/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIFactoryImpl.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIFactoryImpl.java
new file mode 100644
index 0000000..4a048bb
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIFactoryImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.jena.iri.impl;
+
+
+import org.apache.jena.iri.IRI ;
+import org.apache.jena.iri.IRIException ;
+import org.apache.jena.iri.IRIFactoryI ;
+
+abstract public class AbsIRIFactoryImpl implements IRIFactoryI {
+
+    protected abstract IRIFactoryImpl getFactory();
+    public AbsIRIFactoryImpl() {
+    }
+
+//    public IRI create(String s) {
+//        return create(s);
+//    }
+
+    @Override
+    public IRI create(String s) {
+        return create(new IRIImpl(getFactory(),s )
+//                ,
+//                throwEx?AbsIRIImpl.ALL_EXCEPTIONS:
+//                AbsIRIImpl.NO_EXCEPTIONS)
+                );
+    }
+    
+    //@Override
+    @Override
+    public IRI construct(String s) throws IRIException {
+      return throwAnyErrors(create(s));
+    }
+
+    //@Override
+    @Override
+    public IRI construct(IRI i) throws IRIException {
+        return throwAnyErrors(create(i));
+        
+//     
+//     try {
+//     return create(i,true);
+//     } catch (Violation e) {
+//     throw new IRIImplException(e);
+//     }
+    }
+    protected IRI throwAnyErrors(IRI rslt) throws IRIException {
+        if (rslt.hasViolation(false)) {
+            throw new IRIImplException(rslt.violations(false).next());
+//            Iterator it = rslt.exceptions();
+//            while (it.hasNext()){
+//                Violation v = (Violation)it.next();
+//                if (v.isError())
+//                    throw new IRIImplException(v);
+//            } 
+        }
+        return rslt;
+    }
+//    public IRI create(IRI i) {
+//        return create(i);
+//    }
+    @Override
+    abstract public IRI create(IRI i);
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIImpl.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIImpl.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIImpl.java
new file mode 100644
index 0000000..fec96ef
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsIRIImpl.java
@@ -0,0 +1,787 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import java.net.IDN;
+
+import org.apache.jena.iri.* ;
+/*
+import com.vgrs.xcode.idna.Idna;
+import com.vgrs.xcode.idna.Nameprep;
+import com.vgrs.xcode.idna.Punycode;
+import com.vgrs.xcode.util.XcodeException;
+*/
+abstract public class AbsIRIImpl extends  IRI implements 
+        ViolationCodes, IRIComponents {
+
+    private static final int defaultRelative = ABSOLUTE | SAMEDOCUMENT | CHILD
+            | PARENT | GRANDPARENT;
+
+    static String removeDotSegments(String path) {
+        // 5.2.4 step 1.
+        int inputBufferStart = 0;
+        int inputBufferEnd = path.length();
+        StringBuffer output = new StringBuffer();
+        // 5.2.4 step 2.
+        while (inputBufferStart < inputBufferEnd) {
+            String in = path.substring(inputBufferStart);
+            // 5.2.4 step 2A
+            if (in.startsWith("./")) {
+                inputBufferStart += 2;
+                continue;
+            }
+            if (in.startsWith("../")) {
+                inputBufferStart += 3;
+                continue;
+            }
+            // 5.2.4 2 B.
+            if (in.startsWith("/./")) {
+                inputBufferStart += 2;
+                continue;
+            }
+            if (in.equals("/.")) {
+                in = "/"; // don't continue, process below.
+                inputBufferStart += 2; // force end of loop
+            }
+            // 5.2.4 2 C.
+            if (in.startsWith("/../")) {
+                inputBufferStart += 3;
+                removeLastSeqment(output);
+                continue;
+            }
+            if (in.equals("/..")) {
+                in = "/"; // don't continue, process below.
+                inputBufferStart += 3; // force end of loop
+                removeLastSeqment(output);
+            }
+            // 5.2.4 2 D.
+            if (in.equals(".")) {
+                inputBufferStart += 1;
+                continue;
+            }
+            if (in.equals("..")) {
+                inputBufferStart += 2;
+                continue;
+            }
+            // 5.2.4 2 E.
+            int nextSlash = in.indexOf('/', 1);
+            if (nextSlash == -1)
+                nextSlash = in.length();
+            inputBufferStart += nextSlash;
+            output.append(in.substring(0, nextSlash));
+        }
+        // 5.2.4 3
+        return output.toString();
+    }
+
+    private static void removeLastSeqment(StringBuffer output) {
+        int ix = output.length();
+        while (ix > 0) {
+            ix--;
+            if (output.charAt(ix) == '/')
+                break;
+        }
+        output.setLength(ix);
+    }
+
+    private long foundExceptionMask;
+
+    long allErrors;
+
+    abstract long errors(int field);
+
+    abstract SchemeSpecificPart getSchemeSpec();
+    abstract Exception getIDNAException();
+    
+    // void throwExceptions(IRIFactoryImpl f, boolean includeRelative) {
+    // long mask = f.exceptions;
+    // if (!includeRelative)
+    // mask &= ~(1l << RELATIVE_URI);
+    // if (hasExceptionMask(mask)) {
+    // throw (IRIImplUncheckedException) exceptionsMask(mask).next();
+    // }
+    // }
+
+    boolean hasExceptionMask(long mask) {
+        return (allErrors & mask) != 0;
+    }
+
+    private ArrayList<Violation> foundExceptions;
+
+    protected String path;
+/*
+    static private Idna idna;
+    static {
+        try {
+            idna = new Idna(new Punycode(), new Nameprep());
+        } catch (XcodeException e) {
+            System.err.println("Internal error in IDN setup");
+            e.printStackTrace();
+        }
+    }
+*/
+    static final private char hex[] = "0123456789ABCDEF".toCharArray();
+
+    static final Iterator<Violation> nullIterator = new 
ArrayList<Violation>(0).iterator();
+
+    protected static final int NO_EXCEPTIONS = 1;
+
+    protected static final int ALL_EXCEPTIONS = 2;
+
+    protected static final int NOT_RELATIVE_EXCEPTIONS = 3;
+
+    protected static final int PATH_INDEX = Parser.invFields[PATH];
+
+    public AbsIRIImpl() {
+        super();
+    }
+
+    Iterator<Violation> exceptionsMask(final long mask) {
+        createExceptions(mask);
+        return foundExceptions == null ? nullIterator : 
+            new Iterator<Violation>() {
+               private Iterator<Violation> underlying = 
foundExceptions.iterator();
+  
+                private Violation next;
+                @Override
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean hasNext() {
+                    if (next==null) {
+                        while (underlying.hasNext()) {
+                            next = underlying.next();
+                            if (((1l << (next).getViolationCode()) 
+                                    & mask) != 0) 
+                                return true;
+                        }
+                        next = null;
+                        return false;
+                    }
+                    return true;
+                }
+
+                @Override
+                public Violation next() {
+                    if (hasNext()) {
+                        Violation rslt = next;
+                        next = null;
+                        return rslt;
+                    }
+                    throw new NoSuchElementException();
+                }
+            
+        };
+    }
+
+    private void createExceptions(long m) {
+        m &= ~foundExceptionMask;
+        if ((allErrors & m) != 0) {
+            if (foundExceptions == null) {
+                foundExceptions = new ArrayList<>();
+            }
+            for (int i = 0; i < Parser.fields.length; i++) {
+                int f = Parser.fields[i];
+                if ((errors(f) & m) != 0) {
+                    for (int e = 0; e < 64; e++)
+                        if (((1l << e) & m & errors(f)) != 0) {
+                            foundExceptions.add(new ViolationImpl(this, f, e));
+                        }
+
+                }
+            }
+
+        }
+        foundExceptionMask |= m;
+    }
+
+    @Override
+    public boolean isAbsolute() {
+        return has(SCHEME);
+    }
+
+    abstract boolean has(int component);
+
+    @Override
+    public boolean isRelative() {
+        return !has(SCHEME);
+    }
+
+    /*
+     * public boolean isRDFURIReference() { return !hasException(RDF); }
+     * 
+     * public boolean isIRI() { return !hasException(IRI); }
+     * 
+     * public boolean isURIinASCII() { return !hasException(URI); }
+     */
+    // public boolean isVeryBad() {
+    // return false;
+    // }
+    // public boolean isXSanyURI() {
+    // return !hasException(XMLSchema);
+    // }
+    /*
+    public boolean hasException(int conformance) {
+        return hasExceptionMask(getFactory().recsToMask(conformance));
+    }
+
+    public Iterator exceptions(int conformance) {
+        return exceptionsMask(getFactory().recsToMask(conformance));
+    }
+    */
+
+    @Override
+    public boolean hasViolation(boolean includeWarnings) {
+        return hasExceptionMask(getSchemeSpec().getMask(includeWarnings));
+    }
+
+    @Override
+    public Iterator<Violation> violations(boolean includeWarnings) {
+        return exceptionsMask(getSchemeSpec().getMask(includeWarnings));
+    }
+
+    @Override
+    public URL toURL() throws MalformedURLException {
+        return new URL(toASCIIString());
+    }
+
+    // TODO ToAsciiMask
+    static long ToAsciiMask = 
+        ~0l;
+        /*
+        (1l << LTR_CHAR) | (1l << ILLEGAL_CHAR)
+            | (1l << IRI_CHAR) | (1l << UNWISE_CHAR) | (1l << WHITESPACE)
+            | (1l << NOT_XML_SCHEMA_WHITESPACE) | (1l << NON_XML_CHARACTER)
+            | (1l << DOUBLE_DASH_IN_REG_NAME);
+*/
+    @Override
+    public String toASCIIString() throws MalformedURLException {
+        if (hasExceptionMask(ToAsciiMask)) {
+            return createASCIIString();
+        }
+        return toString();
+    }
+
+    private String createASCIIString() throws MalformedURLException {
+        StringBuffer asciiString = new StringBuffer();
+
+        if (has(SCHEME)) {
+            toAscii(asciiString, getScheme(), errors(SCHEME));
+            asciiString.append(':');
+        }
+        if (has(AUTHORITY)) {
+            asciiString.append("//");
+            if (has(USER)) {
+                toAscii(asciiString, getRawUserinfo(), errors(USER));
+                asciiString.append('@');
+            }
+
+            String host = getRawHost();
+            regNameToAscii(asciiString,host);
+            if (has(PORT)) {
+                asciiString.append(':');
+                toAscii(asciiString, get(PORT), errors(USER));
+            }
+        }
+        toAscii(asciiString, getRawPath(), errors(PATH));
+        if (has(QUERY)) {
+            asciiString.append('?');
+            toAscii(asciiString, getRawQuery(), errors(QUERY));
+        }
+        if (has(FRAGMENT)) {
+            asciiString.append('#');
+            toAscii(asciiString, getRawFragment(), errors(FRAGMENT));
+        }
+        return asciiString.toString();
+    }
+
+    private void regNameToAscii(StringBuffer asciiString, String host)
+            throws MalformedURLException {
+        if ((errors(HOST) & ToAsciiMask) == 0) {
+            asciiString.append(host);
+            return;
+        }
+       
+        asciiString.append(domainToAscii(host));
+
+    }
+
+    static CharSequence domainToAscii(String host) throws 
MalformedIDNException {
+        
+        try {
+            return IDNP.toASCII(host, 
IDN.USE_STD3_ASCII_RULES|IDN.ALLOW_UNASSIGNED);
+        } catch (Exception e) {
+            throw new MalformedIDNException(e);
+        } 
+        /*
+        int u[] = new int[host.length()];
+        for (int i = 0; i < host.length(); i++)
+            u[i] = host.charAt(i);
+
+        try {
+            return idna.domainToAscii(u);
+        } catch (XcodeException e) {
+            throw new MalformedIDNException(e);
+        }
+        */
+    }
+
+    private void toAscii(StringBuffer asciiString, String field, long errs) {
+        if ((errs & ToAsciiMask) == 0) {
+            asciiString.append(field);
+            return;
+        }
+        // 3.1 RFC 3987
+        // Step 1c
+
+        // nothing
+
+        // Step 2a
+        /*
+         * Step 2. For each character in 'ucschar' or 'iprivate', apply steps
+         * 2.1 through 2.3 below.
+         * 
+         * We interpret this as any charcater above 127, below 32 and the 
unwise
+         * chars
+         * 
+         * Systems accepting IRIs MAY also deal with the printable characters 
in
+         * US-ASCII that are not allowed in URIs, namely "<", ">", '"', space,
+         * "{", "}", "|", "\", "^", and "`", in step 2 above.
+         */
+        for (int i = 0; i < field.length(); i++) {
+            // TODO Java 1.4/1.5 issue
+            int ch = field.charAt(i);
+            if (ch > 127 || "<>\" {}|\\^`".indexOf(ch) != -1 || ch < 32) {
+                // 2.1
+                byte b[];
+                try {
+                    b = field.substring(i, i + 1).getBytes("utf-8");
+                } catch (UnsupportedEncodingException e) {
+                    throw new RuntimeException("Impossible - utf-8 
unsupported");
+                }
+                // 2.2, 2.3
+                for ( byte aB : b )
+                {
+                    char buf[] = { '%', hex[( aB & ( 255 & ~15 ) ) >> 4], 
hex[aB & 15] };
+
+                    asciiString.append( buf );
+                }
+            } else {
+                asciiString.append(new char[] { (char) ch });
+            }
+        }
+    }
+
+/*
+ * Subroutine for relativize.
+ * 
+ * Relativizing path components is somewhat tricky.
+ * The code is in the method PathRelative.check
+ * which is invoked from relativizePaths
+ * 
+ * There are only three static stateless objects of this class, 
+ * each of which checks for a particular rule.
+ * 
+ * The child object behaves slightly differently, 
+ * with a helper method overridden, and one line of
+ * code specific to that object only.
+ * 
+ */
+    
+    static private final PathRelativize
+        child = new PathRelativize(CHILD, CHILD | PARENT | GRANDPARENT,
+                       "."){
+       @Override
+        String descendentMatch(String descendent) {
+               return maybeDotSlash( descendent);
+       }
+    },
+        parent = new PathRelativize(PARENT, PARENT | GRANDPARENT,
+                       ".."),
+        grandparent = new PathRelativize(GRANDPARENT, GRANDPARENT,
+                               "../..");
+
+    /**
+     * 
+     * @param in     The path from this IRI
+     * @param out    If successful, out[0] contains the answer
+     * @param flags  Currently applicable rules
+     * @param rel    The path to make relative
+     * @return True if the paths were relativized.
+     */
+    private boolean relativizePaths(String in, String[] out, int flags, String 
rel) {
+               if (child.check(in, out, flags, rel)) 
+                       return true;
+               if (parent.check(out[0], out, flags, rel)) 
+                       return true;
+               return grandparent.check(out[0], out, flags, rel);
+       }
+
+    static class PathRelativize {
+       final private int flag;
+       final private int allFlags;
+       final private String replacement;
+       /**
+        * 
+        * @param flag      If this flag is not present then this rule does not 
apply.
+        * @param allFlags  If none of these flags are present then this rule 
and subsequence rules do not apply.
+        * @param replacement     If there is a match, then use this as the 
relative path
+        */
+       PathRelativize(int flag, int allFlags, String replacement) {
+               this.flag = flag;
+               this.replacement = replacement;
+               this.allFlags = allFlags;
+       }
+       /**
+        * Return true if the rule applied.
+        * The result of the rule is returned in out[0]
+        * Return false if the rule did not apply.
+        * The input for the next rule is in out[0]
+        * @param in      Absolute path to use in match
+        * @param out     Result, as above.
+        * @param flags   controlling rule applicability
+        * @param rel     Relative path to use in match
+        * @return
+        */
+       boolean  check(String in, String out[], int flags, String rel) {
+               out[0] = null;
+               if (in==null)
+                       return false;
+               if ((flags & allFlags) == 0)
+                    return false;
+               int ix = in.lastIndexOf('/');
+               if (ix==-1)
+                       return false;
+               if (ix==0 && (flags & ABSOLUTE)!=0 && flag != CHILD)
+                       return false;
+               in = in.substring(0,ix+1);
+               out[0] = in.substring(0,ix);
+               if ((flags & flag) == 0)
+                        return false;
+               if (!rel.startsWith(in))
+                       return false;
+               if (rel.length() == ix+1) {
+                       out[0] = replacement;
+                       return true;
+               }
+               out[0] = descendentMatch(rel.substring(ix+1));
+               return true;
+       }
+       
+       String descendentMatch(String descendent) {
+               return replacement + "/" + descendent;
+       }
+       
+    }
+    
+
+    @Override
+    public IRI relativize(String abs, int flags) {
+        return relativize(new IRIImpl(getFactory(), abs), flags);
+    }
+
+    @Override
+    public IRI relativize(String abs) {
+        return relativize(abs, defaultRelative);
+    }
+
+    @Override
+    public IRI relativize(IRI abs) {
+        return relativize(abs, defaultRelative);
+    }
+    /*
+     * public String relativize(String abs, int flags) { return
+     * relativize(factory.create(abs),abs,flags); }
+     */
+    @Override
+    public IRI relativize(IRI abs, int flags) {
+        String rslt = relativize(abs, null, flags);
+        return rslt == null ? abs : getFactory().create(rslt);
+    }
+    /**
+     * 
+     * @param r
+     * @param def
+     *            Default result if can't make this relative.
+     * @param flags
+     */
+    private String relativize(IRI r, String def, int flags) {
+        if (!has(AUTHORITY))   // we could use the new rules for relative URIs 
for rootless, but I don't like them
+            return def;
+        if (!((AbsIRIImpl)r).has(AUTHORITY))
+            return def;
+        // logger.info("<"+Util.substituteStandardEntities(abs)+">");
+        // logger.info("<"+Util.substituteStandardEntities(r.m_path)+">");
+        boolean net = equal(r.getScheme(), getScheme());
+        boolean absl = net && equal(r.getRawHost(), getRawHost())
+                && equal(getRawUserinfo(), r.getRawUserinfo())
+                && equal(getPort(), r.getPort());
+        boolean same = absl && equal(getRawPath(), r.getRawPath())
+                && equal(getRawQuery(), r.getRawQuery());
+
+        String rslt = r.getRawFragment() == null ? "" : ("#" + r
+                .getRawFragment());
+
+        if (same && (flags & SAMEDOCUMENT) != 0)
+            return rslt;
+
+       String thisPath = getRawPath();
+       String pathToRel = r.getRawPath();
+        if (r.getRawQuery() != null) {
+            rslt = "?" + r.getRawQuery() + rslt;
+               if (equal(thisPath,pathToRel)
+                       && (flags & CHILD)!=0 ) {
+                       return rslt;
+               }
+        }
+        if (absl) {
+               if (pathToRel.length()>0) {
+                       if (thisPath.length()>0) {
+                         String out[] = new String[]{null};
+                         if (relativizePaths(thisPath, out, flags, pathToRel)) 
{
+                               return out[0]+rslt;
+                         }
+                       }
+                rslt = r.getRawPath() + rslt;
+                if (absl && (flags & ABSOLUTE) != 0) {
+                    return rslt;
+                }
+               }
+        } else 
+               rslt = r.getRawPath() + rslt;
+        if (net && (flags & NETWORK) != 0) {
+            return "//"
+                    + (r.getRawUserinfo() == null ? ""
+                            : (r.getRawUserinfo() + "@")) + r.getRawHost()
+                    + (r.getPort() == IRI.NO_PORT ? "" : (":" + 
((AbsIRIImpl)r).get(PORT))) + rslt;
+
+        }
+        return def;
+    }
+
+
+       static private String maybeDotSlash(String path) {
+        int colon = path.indexOf(':');
+        if (colon == -1)
+            return path;
+        int slash = path.indexOf('/');
+        if (slash==-1 || slash>colon)
+            return "./"+path;
+        return path;
+    }
+
+    static private String getLastSlash(String s) {
+        int ix = s.lastIndexOf('/', s.length() - 2);
+        return s.substring(0, ix + 1);
+    }
+
+    private boolean equal(String s1, String s2) {
+        return s1 == null ? s2 == null : s1.equals(s2);
+    }
+
+    private boolean equal(int s1, int s2) {
+        return s1 == s2;
+    }
+
+    public Iterator<Violation> allViolations() {
+        return exceptionsMask(~0l);
+    }
+
+    @Override
+   public String getRawUserinfo() {
+        return get(USER);
+    }
+
+    @Override
+   public int getPort() {
+        String port = get(PORT);
+        if (port == null)
+            return IRI.NO_PORT;
+        try {
+            int v = Integer.parseInt(port);
+            if (v<0)
+                return IRI.ILLFORMED_PORT;
+            return v;
+        } catch (Exception e) {
+            return IRI.ILLFORMED_PORT;
+        }
+    }
+
+    @Override
+    public String getRawQuery() {
+        return get(QUERY);
+    }
+
+    @Override
+    public String getRawFragment() {
+        return get(FRAGMENT);
+    }
+
+    @Override
+    public String getRawHost() {
+        return get(HOST);
+    }
+
+    @Override
+    public String getScheme() {
+        return get(SCHEME);
+    }
+
+    abstract String get(int comp);
+
+    @Override
+    public String getRawPath() {
+        return path;
+    }
+
+    @Override
+    public boolean isRootless() {
+        if (!has(SCHEME))
+            return false;
+        if (has(AUTHORITY))
+            return false;
+        if (path.equals(""))
+            return false;
+        if (path.charAt(0) == '/')
+            return false;
+        return true;
+    }
+
+    abstract String pathRemoveDots();
+
+    abstract boolean dotsOK();
+
+    @Override
+    public String getRawAuthority() {
+        return get(AUTHORITY);
+    }
+
+    @Override
+    public IRI create(IRI i) {
+        return new ResolvedRelativeIRI(this, (AbsIRIImpl) getFactory()
+                .create(i));
+    }
+
+    @Override
+    public IRI create(String s) {
+        return create(new IRIImpl(getFactory(), s) );
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null)
+            return false;
+        if (!(o instanceof IRI))
+            return false;
+        return toString().equals(o.toString());
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    @Override
+    public String getAuthority() {
+        return getCooked(AUTHORITY);
+    }
+
+    @Override
+    public String getFragment() {
+        return getCooked(FRAGMENT);
+    }
+
+    @Override
+    public String getHost() {
+        return getCooked(HOST);
+    }
+
+    @Override
+    public String getPath() {
+        return getCooked(PATH);
+    }
+
+    @Override
+    public String getQuery() {
+        return getCooked(QUERY);
+    }
+
+    @Override
+    public String getUserinfo() {
+        return getCooked(USER);
+    }
+
+    private String getCooked(int component) {
+        // TODO getCooked
+       throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    public IRI normalize(boolean useDns) {
+        // TODO normalize
+       throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /*
+     * Bidirectional IRIs MUST be rendered in the same way as they would be if
+     * they were in a left-to-right embedding; i.e., as if they were preceded 
by
+     * U+202A, LEFT-TO-RIGHT EMBEDDING (LRE), and followed by U+202C, POP
+     * DIRECTIONAL FORMATTING (PDF).
+     * 
+     */
+    @Override
+    public String toDisplayString() {
+        return "\u202A" + toString() + "\u202C";
+    }
+
+    // TODO http://example.com/&#x10300;&#x10301;&#x10302 =>
+    // http://example.com/%F0%90%8C%80%F0%90%8C%81%F0%90%8C%82
+
+    @Override
+    public String getASCIIHost() throws MalformedURLException {
+        StringBuffer asciiString = new StringBuffer();
+
+        String host = getRawHost();
+        if (host==null)
+            return null;
+        regNameToAscii(asciiString,host);
+        return asciiString.toString();
+    }
+
+    @Override
+    public boolean ladderEquals(IRI iri, int other) {
+        // TODO ladderEquals
+       throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    public int ladderEquals(IRI iri) {
+        // TODO ladderEquals
+       throw new UnsupportedOperationException("not yet implemented");
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsLexer.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsLexer.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsLexer.java
new file mode 100644
index 0000000..ae08392
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/AbsLexer.java
@@ -0,0 +1,255 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.text.Normalizer ;
+import java.lang.Character.UnicodeBlock ;
+
+import org.apache.jena.iri.ViolationCodes ;
+
+abstract class AbsLexer implements ViolationCodes {
+
+    /* user code: */
+    protected Parser parser;
+    protected int range;
+
+    /*
+    yyreset(null);
+    this.zzAtEOF = true;
+    int length = parser.end(range)-parser.start(range);
+    zzEndRead = length;
+    while (length > zzBuffer.length)
+        zzBuffer = new char[zzBuffer.length*2];
+
+    */
+    synchronized public void analyse(Parser p,int r) {
+        parser = p;
+        range = r;
+        if (!parser.has(range)) 
+            return;
+        parser.uri.getChars(
+                parser.start(range),
+                parser.end(range),
+                zzBuffer(),
+                0);
+       try {
+            yylex();
+       }
+       catch (java.io.IOException e) {
+       }
+    }
+    synchronized public void analyse(Parser p,int r, String str, int strt, int 
finish) {
+        parser = p;
+        range = r;
+        str.getChars(
+                strt,
+                finish,
+                zzBuffer(),
+                0);
+       try {
+            yylex();
+       }
+       catch (java.io.IOException e) {
+       }
+    }
+    
+    
+    abstract  int yylex() throws java.io.IOException;
+    abstract char[] zzBuffer();
+    
+    protected void error(int e) {
+        parser.recordError(range,e);
+    }
+    
+    final protected void rule(int rule) {
+        parser.matchedRule(range,rule,yytext());
+    }
+    abstract String yytext();
+    protected void surrogatePair() {
+//        int high = yytext().charAt(0);
+//        int low = yytext().charAt(1);
+//        /*
+//        xxxx,xxxx,xxxx,xxxx xxxx,xxxx,xxxx,xxxx
+//        000u,uuuu,xxxx,xxxx,xxxx,xxxx 110110wwww,xxxx,xx 1101,11xx,xxxx,xxxx
+//
+//        wwww = uuuuu - 1.
+//        */
+//        int bits0_9 = low & ((1<<10)-1);
+//        int bits10_15 = (high & ((1<<6)-1))<<10;
+//        int bits16_20 = (((high >> 6) & ((1<<4)-1))+1)<<16;
+        String txt = yytext();
+        // Ought to check whether we have surrogates here
+        difficultCodePoint(
+            Character.toCodePoint(txt.charAt(0), txt.charAt(1)),
+            txt);
+    }
+
+    private void difficultCodePoint(int codePoint, String txt) {
+        /* Legal XML
+        #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+         */
+        error(NON_URI_CHARACTER);
+        if (codePoint> 0xD7FF && codePoint < 0xE000)
+            error(NON_XML_CHARACTER);
+        if (codePoint>0xFFFD && codePoint < 0x10000)
+            error(NON_XML_CHARACTER);
+        
+        /* Discouraged XML chars
+        [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF],
+        [#1FFFE-#x1FFFF], [#2FFFE-#x2FFFF], [#3FFFE-#x3FFFF],
+        [#4FFFE-#x4FFFF], [#5FFFE-#x5FFFF], [#6FFFE-#x6FFFF],
+        [#7FFFE-#x7FFFF], [#8FFFE-#x8FFFF], [#9FFFE-#x9FFFF],
+        [#AFFFE-#xAFFFF], [#BFFFE-#xBFFFF], [#CFFFE-#xCFFFF],
+        [#DFFFE-#xDFFFF], [#EFFFE-#xEFFFF], [#FFFFE-#xFFFFF],
+        [#10FFFE-#x10FFFF].
+        */
+        
+        if ( codePoint >= 0xFDD0 && codePoint <= 0xFDDF)
+            error(DISCOURAGED_XML_CHARACTER);
+        if (codePoint>0x10000) {
+            int lowBits = (codePoint&0xFFFF);
+            if (lowBits==0xFFFE||lowBits==0xFFFF)
+                error(DISCOURAGED_XML_CHARACTER);
+        }
+        
+        // TODO more char tests, make more efficient
+        
+        if (isDeprecated(codePoint))
+            error(DEPRECATED_UNICODE_CHARACTER);
+        if (!Character.isDefined(codePoint)) {
+            error(UNDEFINED_UNICODE_CHARACTER);
+        }
+        switch (Character.getType(codePoint)) {
+        case Character.PRIVATE_USE:
+            error(PRIVATE_USE_CHARACTER);
+            break;
+        case Character.CONTROL:
+            error(UNICODE_CONTROL_CHARACTER);
+            break;
+        case Character.UNASSIGNED:
+            error(UNASSIGNED_UNICODE_CHARACTER);
+            break;
+        }
+        
+        if (!Normalizer.isNormalized(txt, Normalizer.Form.NFC)) {
+            error(NOT_NFC);
+        }
+        
+        if (!Normalizer.isNormalized(txt, Normalizer.Form.NFKC)) {
+            error(NOT_NFKC);
+        }
+        
+        if (Character.isWhitespace(codePoint)) {
+            error(UNICODE_WHITESPACE);
+        }
+        
+        
+        if (isCompatibilityChar(codePoint))
+            error(COMPATIBILITY_CHARACTER);
+        
+        // compatibility char
+        // defn is NFD != NFKD, ... hmmm
+        
+    }
+
+    private boolean isCompatibilityChar(int codePoint) {
+        
+        // Slight optimistation inherited from ICU4J version
+        // Not sure it's worth it since we can't do some of the ICU4J checks
+        UnicodeBlock block = UnicodeBlock.of(codePoint);
+
+        if (block == UnicodeBlock.CJK_COMPATIBILITY) {
+            /*(U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21,
+            U+FA23, U+FA24, U+FA27, U+FA28, and U+FA29)
+             */
+            switch (codePoint) {
+                case 0xFA0E:
+                case 0xFA0F:
+                case 0xFA11:
+                case 0xFA13:
+                case 0xFA14:
+                case 0xFA1F:
+                case 0xFA21:
+                case 0xFA23:
+                case 0xFA24:
+                case 0xFA27:
+                case 0xFA28:
+                case 0xFA29:
+                    return false;
+                default:
+                    return true;
+            }
+        } else if (block == UnicodeBlock.CJK_COMPATIBILITY_FORMS
+                || block == 
UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
+                || block == UnicodeBlock.CJK_RADICALS_SUPPLEMENT
+                || block == UnicodeBlock.KANGXI_RADICALS
+                || block == UnicodeBlock.HANGUL_COMPATIBILITY_JAMO) {
+            return true;
+        }
+
+        // codepoint -> charsequence ought to be easy
+        String cp = new String(new int[]{codePoint}, 0, 1);
+        
+        // Compatibility char is where NFD differs from NFKD
+        return
+        !Normalizer.normalize(cp,Normalizer.Form.NFD).equals(
+                Normalizer.normalize(cp,Normalizer.Form.NFKD)
+                );
+       
+    }
+
+    protected void difficultChar() {
+        difficultCodePoint(yytext().charAt(0),yytext());
+    }
+    
+    /**
+     * Unicode deprecated characters. Not available from standard java libs.
+     * Taken from {@link 
"http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B:deprecated:%5D"}
+     * @param codePoint
+     * @return 
+     */
+    private static boolean isDeprecated(int codePoint) {
+        
+        // Common case
+        if (codePoint < 0x0149) return false;
+        
+        if (codePoint >= 0xE0020 && codePoint <= 0xE007F) return true;
+        
+        switch (codePoint) {
+            case 0x0149:
+            case 0x0673:
+            case 0x0F77:
+            case 0x0F79:
+            case 0x17A3:
+            case 0x17A4:
+            case 0x206A:
+            case 0x206B:
+            case 0x206C:
+            case 0x206D:
+            case 0x206E:
+            case 0x206F:
+            case 0x2329:
+            case 0x232A:
+            case 0xE0001:
+                return true;
+            default:
+                return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/BuildViolationCodes.java
----------------------------------------------------------------------
diff --git 
a/jena-iri/src/main/java/org/apache/jena/iri/impl/BuildViolationCodes.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/BuildViolationCodes.java
new file mode 100644
index 0000000..27999bf
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/BuildViolationCodes.java
@@ -0,0 +1,42 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.io.File;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+public class BuildViolationCodes {
+    public static void main(String[] args) throws TransformerException, 
TransformerFactoryConfigurationError {
+        Transformer xsl =
+        TransformerFactory.newInstance().newTransformer(
+                new StreamSource(new 
File("src/main/xml/org/apache/jena/iri/impl/viol2java.xsl"))
+                );
+        xsl.transform(
+                new StreamSource(new 
File("src/main/xml/org/apache/jena/iri/impl/violations.xml")),
+                new StreamResult(new 
File("src/main/java/org/apache/jena/iri/ViolationCodes.java"))
+                        
+        );
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPattern.java
----------------------------------------------------------------------
diff --git 
a/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPattern.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPattern.java
new file mode 100644
index 0000000..fad1559
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPattern.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.jena.iri.ViolationCodes ;
+
+
+public class ComponentPattern implements ViolationCodes {
+    final Pattern pattern;
+
+    final GroupAction actions[];
+
+    static final List<Pattern> allPatterns = new ArrayList<>();
+
+    ComponentPattern(String p) {
+        ComponentPatternParser parser = new ComponentPatternParser(p);
+        pattern = parser.get();
+        actions = parser.actions();
+//        System.err.println(allPatterns.size() + ": " + p + " ==> "
+//                + pattern.toString());
+        allPatterns.add(pattern);
+    }
+
+    
+
+    public void analyse(Parser parser, int range) {
+        Matcher m = pattern.matcher(parser.get(range));
+        if (!m.matches()) {
+            parser.recordError(range, SCHEME_PATTERN_MATCH_FAILED);
+            return;
+        }
+        for (int g = 1; g <= m.groupCount(); g++)
+            if (m.start(g) != -1)
+                actions[g].check(m, parser, range);
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPatternParser.java
----------------------------------------------------------------------
diff --git 
a/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPatternParser.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPatternParser.java
new file mode 100644
index 0000000..b510893
--- /dev/null
+++ 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/ComponentPatternParser.java
@@ -0,0 +1,323 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.jena.iri.ViolationCodes ;
+
+
+public class ComponentPatternParser implements ViolationCodes {
+    static String separators = 
"([(](?![?]))|([(][?])|([)])|(\\[)|(\\])|([@][{])|([}]|[a-z]-[a-z])";
+
+    static final int OPEN_PAREN = 1;
+
+    static final int OPEN_NON_CAPTURING_PAREN = 2;
+
+    static final int CLOSE_PAREN = 3;
+
+    static final int OPEN_SQ = 4;
+
+    static final int CLOSE_SQ = 5;
+
+    static final int OPEN_VAR = 6;
+
+    static final int CLOSE_BRACE = 7;
+    
+    static final int LOWER_CASE_RANGE = 8;
+
+    static final int OTHER = -1;
+
+    static final Pattern keyword = Pattern.compile(separators);
+
+    /* .NET port does not like this. Reworked.
+     *
+    static final Pattern splitter = Pattern.compile("(?=" + separators
+            + ")|(?<=" + separators + ")");
+            
+    
+    public ComponentPatternParser(String p) {
+        split = splitter.split(p);
+        field = 0;
+        classify = new int[split.length];
+        for (int i = 0; i < split.length; i++)
+            classify[i] = classify(split[i]);
+        while (field < split.length)
+            next();
+//        System.err.println(p + " ==> "+ rslt.toString());
+        pattern = Pattern.compile(rslt.toString());
+    }
+*/
+    // working data
+    final String split[];
+
+    final int classify[];
+
+    int field;
+
+    int groupCount;
+
+    // result data
+    final StringBuffer rslt = new StringBuffer();
+
+    int shouldLowerCase;
+
+    int mustLowerCase;
+
+    int hostNames;
+    
+    final Pattern pattern;
+    
+    static final String emptyStringArray[] = new String[0];
+
+    static private String[] mySplit(String p) {
+        //return splitter.split(p); 
+        
+        Matcher m = keyword.matcher(p);
+        List<String> rslt = new ArrayList<>();
+        int pos = 0;
+//        rslt.add("");
+        while (m.find()) {
+            if (m.start()>pos || pos==0) {
+                rslt.add(p.substring(pos,m.start()));
+            }
+            rslt.add(p.substring(m.start(),m.end()));
+            pos = m.end();
+        }
+        if (pos < p.length())
+            rslt.add(p.substring(pos));
+        
+//        m.
+//        String preSplit[] = keyword.split(p);
+//        String rslt[] = new String[preSplit.length*2];
+        
+        return rslt.toArray(emptyStringArray);
+        
+    }
+    
+//    static private String[] mySplitx(String p) {
+//        String r[] = mySplit(p);
+//        String s[] = splitter.split(p);
+//        if (r.length!=s.length) {
+//            System.err.println("Bad lengths: "+p+","+r.length+","+s.length);
+//        }
+//        for (int i=0;i<r.length && i <s.length;i++)
+//            if (!r[i].equals(s[i]))
+//                System.err.println("Bad component: "+p+","+r[i]+","+s[i]);
+//        return r;
+//        
+//        
+//    }
+    // end result data
+    public ComponentPatternParser(String p) {
+        split = mySplit(p);
+        field = 0;
+        classify = new int[split.length];
+        for (int i = 0; i < split.length; i++)
+            classify[i] = classify(split[i]);
+        while (field < split.length)
+            next();
+//        System.err.println(p + " ==> "+ rslt.toString());
+        pattern = Pattern.compile(rslt.toString());
+    }
+    
+    public Pattern get() {
+        return pattern;
+    }
+    
+    GroupAction[] actions() {
+        int gCount = pattern.matcher("").groupCount()+1;
+        GroupAction result[] = new GroupAction[gCount];
+        for (int i=1;i<gCount;i++) {
+            int g = 1<<i;
+            if ((mustLowerCase & g)!=0)
+                result[i] = new ErrorAction(SCHEME_REQUIRES_LOWERCASE);
+            else if ((shouldLowerCase & g)!=0)
+                result[i] = new ErrorAction(SCHEME_PREFERS_LOWERCASE);
+            else if ((hostNames & g)!=0)
+                result[i] = new HostAction(i);
+            else
+                result[i] = GroupAction.NoAction;
+        }
+        return result;
+    }
+
+    private int classify(String string) {
+        Matcher m = keyword.matcher(string);
+        if (!m.matches())
+            return OTHER;
+        for (int i = 1; i <= m.groupCount(); i++)
+            if (m.start(i) != -1)
+                return i;
+        throw new IllegalStateException(
+                "IRI code internal error: no group matched.");
+    }
+
+    private void untilCloseSq() {
+        while (classify[field - 1] != CLOSE_SQ) {
+            if (field >= split.length)
+                throw new IllegalArgumentException(
+                        "Internal IRI code error. Did not find CLOSE_SQ in 
until().");
+            add();
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    private void next() {
+        switch (classify[field]) {
+        case CLOSE_SQ:
+            throw new IllegalArgumentException(
+                    "Found unexpected ], either pattern syntax error, or 
limitation of IRI code.");
+        case OPEN_SQ:
+            add();
+            untilCloseSq();
+            break;
+        case OPEN_VAR:
+            field++;
+            rslt.append("(");
+            groupCount++;
+            if (split[field].equals("host")) {
+                addHost();
+            } else {
+                if (split[field].equals("shouldLowerCase")) {
+
+                    shouldLowerCase |= (1 << groupCount);
+                } else if (split[field].equals("mustLowerCase")) {
+
+                    mustLowerCase |= (1 << groupCount);
+                } else {
+                    throw new IllegalArgumentException("No macro: "
+                            + split[field]);
+                }
+                addLowerCase();
+            }
+            break;
+
+        case OPEN_PAREN:
+            groupCount++;
+        // fall through
+        case OPEN_NON_CAPTURING_PAREN:
+        case CLOSE_PAREN:
+        case CLOSE_BRACE:
+        case LOWER_CASE_RANGE:
+        case OTHER:
+            add();
+            return;
+        default:
+            throw new IllegalStateException("IRI code internal error.");
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    private void addLowerCase() {
+        int sqCount=0;
+        field++;
+        if (classify[field]!=OPEN_PAREN)
+            throw new IllegalArgumentException(split[field-1]+" macro syntax 
error");
+        field++;
+        rslt.append("?:(?:");  // make group non-capturing.
+        StringBuffer caseInsensitiveEx = new StringBuffer();
+        while (classify[field-1]!=CLOSE_PAREN || sqCount>0 ) {
+            if (field >= split.length)
+                throw new IllegalArgumentException(
+                        "Internal IRI code error. Did not find CLOSE_PAREN in 
addLowerCase().");
+           
+            switch (classify[field]) {
+            case OPEN_SQ:
+                sqCount++;
+                caseInsensitiveEx.append('[');
+                break;
+            case CLOSE_SQ:
+                sqCount--;
+                caseInsensitiveEx.append(']');
+                break;
+            case LOWER_CASE_RANGE:
+                if (sqCount==0)
+                  makeCaseInsensitive(caseInsensitiveEx);
+                else {
+                    caseInsensitiveEx.append(split[field]);
+                    
caseInsensitiveEx.append((char)(split[field].charAt(0)-'a'+'A'));
+                    caseInsensitiveEx.append('-');
+                    
caseInsensitiveEx.append((char)(split[field].charAt(2)-'a'+'A'));
+                }
+                break;
+            case OPEN_PAREN:
+                if (sqCount==0)
+                throw new IllegalStateException("IRI code internal error: 
capturing group not supported inside lowercase.");
+                // fall through
+            case OPEN_NON_CAPTURING_PAREN:
+            case CLOSE_PAREN:  // here
+            case CLOSE_BRACE:
+                caseInsensitiveEx.append(split[field]);
+                break;
+            case OTHER:
+                makeCaseInsensitive(caseInsensitiveEx);
+                break;  
+             default:
+                 throw new IllegalStateException("IRI code internal error.");
+           }
+            add();
+        }
+        if (classify[field]!=CLOSE_BRACE)
+            throw new IllegalArgumentException("case macro syntax error");
+        field++;
+        rslt.append("|("); // start capturing group
+        rslt.append(caseInsensitiveEx);
+        rslt.append(")");
+    }
+
+    private void makeCaseInsensitive(StringBuffer caseInsensitiveEx) {
+        for (int i=0;i<split[field].length();i++) {
+            char c = split[field].charAt(i);
+            if (c>='a' && c<='z') {
+                caseInsensitiveEx.append('[');
+                caseInsensitiveEx.append(c);
+                caseInsensitiveEx.append((char)(c-'a'+'A'));
+                caseInsensitiveEx.append(']');
+            }
+        }
+    }
+
+    private void addHost() {
+        hostNames |= (1 << groupCount);
+        field++;
+        if (classify[field]!=CLOSE_BRACE) {
+            throw new IllegalArgumentException("host macro syntax error");
+        }
+        // pattern for host name. A sequence of chars that are not reserved.
+        // or an IP v6 or future address which starts and ends with [ ] and may
+        // include :.
+        
rslt.append("[^\\[\\]:/?#@!$&'()*+,;=]*|\\[[^\\[\\]/?#@!$&'()*+,;=]*\\])");
+        field++;
+    }
+
+    private void add() {
+        rslt.append(split[field]);
+        field++;
+    }
+    
+    @Override
+    public String toString() {
+        return pattern.pattern();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/ErrorAction.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/ErrorAction.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/ErrorAction.java
new file mode 100644
index 0000000..19df2dd
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/ErrorAction.java
@@ -0,0 +1,33 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.util.regex.Matcher;
+
+public class ErrorAction extends GroupAction {
+    final private int eCode;
+    ErrorAction(int code){
+        this.eCode = code;
+    }
+    @Override
+    public void check(Matcher m, Parser parser, int range) {
+        parser.recordError(range,eCode);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/Force.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/Force.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/Force.java
new file mode 100644
index 0000000..0a56142
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/Force.java
@@ -0,0 +1,35 @@
+/*
+ * 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.jena.iri.impl;
+
+public interface Force {
+    static final int SHOULD = 0;
+    static final int DNS = 1;
+    static final int MINTING = 2;
+    static final int SECURITY = 3;
+//    static final int SCHEME_SPECIFIC = 4;
+    static final int MUST = 4;
+    static final int SIZE = 5;
+    static final int minting = 1 << MINTING;
+    static final int must = 1 << MUST;
+    static final int should = 1 << SHOULD;
+    static final int dns = 1 << DNS;
+    static final int security = 1 << SECURITY;
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/GroupAction.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/GroupAction.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/GroupAction.java
new file mode 100644
index 0000000..b1c03eb
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/GroupAction.java
@@ -0,0 +1,33 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.util.regex.Matcher;
+
+public abstract class GroupAction {
+
+    public static final GroupAction NoAction = new GroupAction() {
+        @Override
+        public void check(Matcher m, Parser parser, int range) {
+        }
+    };
+
+    abstract public void check(Matcher m, Parser parser, int range);
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/HostAction.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/HostAction.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/HostAction.java
new file mode 100644
index 0000000..40cc55c
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/HostAction.java
@@ -0,0 +1,34 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.util.regex.Matcher;
+
+public class HostAction extends GroupAction {
+    final private int group;
+    HostAction(int group) {
+        this.group = group;
+    }
+    @Override
+    public void check(Matcher m, Parser parser, int range) {
+        Parser.hostLexer().analyse(parser,range,m.group(group));
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/IDNP.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/IDNP.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/IDNP.java
new file mode 100644
index 0000000..fdf1c46
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/IDNP.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * Licensed 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.jena.iri.impl;
+
+import java.net.IDN;
+
+/**
+ * IDNP: IDN Patched
+ * 
+ * A wrapper around java.net.IDN to avoid a bug when checking result.
+ * It looks like the IDN is apply checks before fully converting, so this 
defers
+ * a similar check until the end.
+ */
+public class IDNP {
+    
+    public static String toASCII(String host, int flags) {
+        if ((flags & IDN.USE_STD3_ASCII_RULES) != 0) {
+            return check(IDN.toASCII(host, flags ^ IDN.USE_STD3_ASCII_RULES));
+        } else {
+            return IDN.toASCII(host, flags);
+        }
+    }
+    
+    // Step through each part of the host and ensure that they conform
+    private static String check(final String asciiHost) {
+        String[] parts = asciiHost.split("\\.");
+        for (String part: parts) checkPart(part);
+        return asciiHost;
+    }
+    
+    // Part check: no leading or trailing hyphens, hyphens and alphanumerics.
+    // We try to follow java.net.IDN behaviour in our exceptions, in 
anticipation
+    // of dumping this class.
+    private static void checkPart(String part) {
+        if (part.charAt(0) == '-' || 
+                part.charAt(part.length() - 1) == '-') {
+            throw new IllegalArgumentException("Has leading or trailing 
hyphen");
+        }
+        for (int i = 0; i < part.length(); i++) {
+            char c = part.charAt(i);
+            // Host is limited to hyphens and alpha numerics
+            if (c != '-' &&
+                    !(c >= '0' && c <= '9') &&
+                    !(c >= 'a' && c <= 'z') &&
+                    !(c >= 'A' && c <= 'Z')) {
+                throw new IllegalArgumentException("Contains non-LDH 
characters");
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIExamples.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIExamples.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIExamples.java
new file mode 100644
index 0000000..442b6dd
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIExamples.java
@@ -0,0 +1,40 @@
+/*
+ * 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.jena.iri.impl;
+
+public class IRIExamples {
+
+    protected final String badExamples[];
+    protected final String goodExamples[];
+
+    public IRIExamples(String[] badExamples, String[] goodExamples) {
+
+      this.badExamples = badExamples;
+      this.goodExamples = goodExamples;
+    }
+
+    public String[] getBadExamples() {
+        return badExamples;
+    }
+
+    public String[] getGoodExamples() {
+        return goodExamples;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIFactoryImpl.java
----------------------------------------------------------------------
diff --git 
a/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIFactoryImpl.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIFactoryImpl.java
new file mode 100644
index 0000000..ad45840
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIFactoryImpl.java
@@ -0,0 +1,498 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.io.UnsupportedEncodingException;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.apache.jena.iri.IRI ;
+import org.apache.jena.iri.IRIComponents ;
+import org.apache.jena.iri.ViolationCodes ;
+
+
+public class IRIFactoryImpl 
+  extends AbsIRIFactoryImpl
+  implements ViolationCodes, Force, IRIComponents {
+
+public static final int UNKNOWN_SYNTAX = -4;
+    //    boolean throwUncheckedExceptions = false;
+    /*
+    static final long conformanceMasks[] = {
+            // RFC3986
+              (1l<<ILLEGAL_CHAR) 
+              |(1l<<ILLEGAL_PERCENT_ENCODING)
+              |(1l<<EMPTY_SCHEME)
+              |(1l<<IP_V4_HAS_FOUR_COMPONENTS)
+              |(1l<<IP_V4_OCTET_RANGE)
+              |(1l<<IP_V6_OR_FUTURE_ADDRESS_SYNTAX)
+              |(1l<<IRI_CHAR)
+              |(1l<<LTR_CHAR)
+              |(1l<<NOT_XML_SCHEMA_WHITESPACE)
+              |(1l<<SCHEME_MUST_START_WITH_LETTER)
+              |(1l<<UNWISE_CHAR)
+              |(1l<<WHITESPACE)
+              |(1l<<ARBITRARY_CHAR)
+              ,
+            // RFC3987
+              (1l<<ILLEGAL_CHAR) 
+              |(1l<<ILLEGAL_PERCENT_ENCODING)
+              |(1l<<EMPTY_SCHEME)
+              |(1l<<IP_V4_HAS_FOUR_COMPONENTS)
+              |(1l<<IP_V4_OCTET_RANGE)
+              |(1l<<IP_V6_OR_FUTURE_ADDRESS_SYNTAX)
+              |(1l<<LTR_CHAR)
+              |(1l<<NOT_XML_SCHEMA_WHITESPACE)
+              |(1l<<SCHEME_MUST_START_WITH_LETTER)
+              |(1l<<UNWISE_CHAR)
+              |(1l<<WHITESPACE)
+              |(1l<<ARBITRARY_CHAR)
+              ,
+            // RDF
+              (1l<<ILLEGAL_CHAR) 
+              |(1l<<ILLEGAL_PERCENT_ENCODING)
+              |(1l<<EMPTY_SCHEME)
+              |(1l<<IP_V4_HAS_FOUR_COMPONENTS)
+              |(1l<<IP_V4_OCTET_RANGE)
+              |(1l<<IP_V6_OR_FUTURE_ADDRESS_SYNTAX)
+              |(1l<<SCHEME_MUST_START_WITH_LETTER)
+              |(1l<<RELATIVE_URI)
+              ,
+            // XLink
+              (1l<<ILLEGAL_CHAR) 
+              |(1l<<ILLEGAL_PERCENT_ENCODING)
+              |(1l<<EMPTY_SCHEME)
+              |(1l<<IP_V4_HAS_FOUR_COMPONENTS)
+              |(1l<<IP_V4_OCTET_RANGE)
+              |(1l<<IP_V6_OR_FUTURE_ADDRESS_SYNTAX)
+              |(1l<<SCHEME_MUST_START_WITH_LETTER)
+              |(1l<<NON_XML_CHARACTER)
+              ,
+            // XMLSchema
+              (1l<<ILLEGAL_CHAR) 
+              |(1l<<ILLEGAL_PERCENT_ENCODING)
+              |(1l<<EMPTY_SCHEME)
+              |(1l<<IP_V4_HAS_FOUR_COMPONENTS)
+              |(1l<<IP_V4_OCTET_RANGE)
+              |(1l<<IP_V6_OR_FUTURE_ADDRESS_SYNTAX)
+              |(1l<<SCHEME_MUST_START_WITH_LETTER)
+              |(1l<<NOT_XML_SCHEMA_WHITESPACE)
+              |(1l<<NON_XML_CHARACTER)
+              ,
+            // IDN
+//              (1l<<ACE_PREFIX)
+              0
+              ,
+            // Should
+              (1l<<LOWERCASE_PREFERRED) 
+              |(1l<<PORT_SHOULD_NOT_BE_EMPTY)
+              |(1l<<PORT_SHOULD_NOT_START_IN_ZERO)
+    //          |(1l<<SCHEME_NAMES_SHOULD_BE_LOWER_CASE)
+              |(1l<<PERCENT_ENCODING_SHOULD_BE_UPPERCASE)
+              |(1l<<IPv6ADDRESS_SHOULD_BE_LOWERCASE)
+              |(1l<<USE_PUNYCODE_NOT_PERCENTS)
+              ,
+            // Minting
+      /* consider HAS_PASSWORD vs LOWER_CASE_PREFERRED
+       * The former should be an error unless switched
+       * off (but it can be, unlike a MUST), whereas the 
+       * latter should be a warning by default.
+       * /
+              (1l<<LOWERCASE_PREFERRED) 
+              |(1l<<PORT_SHOULD_NOT_BE_EMPTY)
+              |(1l<<PORT_SHOULD_NOT_START_IN_ZERO)
+    //          |(1l<<SCHEME_NAMES_SHOULD_BE_LOWER_CASE)
+              |(1l<<PERCENT_ENCODING_SHOULD_BE_UPPERCASE)
+              |(1l<<IPv6ADDRESS_SHOULD_BE_LOWERCASE)
+              |(1l<<USE_PUNYCODE_NOT_PERCENTS)
+              ,
+            // DNS
+              (1l<<NOT_DNS_NAME)
+              ,
+        };
+        */
+    protected long errors;
+    protected long warnings;
+    
+    protected Set<Specification> specs = new HashSet<>();
+
+    public IRIFactoryImpl() {
+    }
+
+    public IRIFactoryImpl(IRIFactoryImpl template) {
+        if (backwardCompatibleRelativeRefs.size()==Integer.MAX_VALUE)
+          backwardCompatibleRelativeRefs = 
template.backwardCompatibleRelativeRefs;
+        else 
+               backwardCompatibleRelativeRefs = new 
HashSet<>(backwardCompatibleRelativeRefs);
+        encoding = template.encoding;
+        errors = template.errors;
+        prohibited = template.prohibited;
+        required = template.required;
+        warnings = template.warnings;
+        System.arraycopy(template.asErrors,0,asErrors,0,asErrors.length);
+        System.arraycopy(template.asWarnings,0,asWarnings,0,asWarnings.length);
+        for ( Entry<String, SchemeSpecificPart> entry : 
template.schemes.entrySet() )
+        {
+            SchemeSpecificPart p = entry.getValue();
+            if ( p.withScheme() )
+            {
+                schemes.put( entry.getKey(), new WithScheme( (WithScheme) p ) 
);
+            }
+            else if ( p.port() != IRI.NO_PORT )
+            {
+                schemes.put( entry.getKey(), new NoScheme( p.port() ) );
+            }
+        }
+    }
+
+    /*
+    protected long recsToMask(int recs) {
+        long  mask = 0;
+        for (int i=0; recs != 0 && i<conformanceMasks.length; i++) {
+            if ((recs & (1<<i)) != 0) {
+                mask |= conformanceMasks[i];
+                recs &= ~(1<<i);
+            }
+        }
+        return mask;
+    }
+*/
+    private final long getMask(boolean includeWarnings) {
+        
+        return includeWarnings?(errors|warnings):errors;
+    }
+
+    @Override
+    protected IRIFactoryImpl getFactory() {
+        return this;
+    }
+    
+    @Override
+    public IRI create(IRI i) {
+        if (i instanceof AbsIRIImpl && 
+                ((AbsIRIImpl)i).getFactory()==this)
+            return i;
+        return 
+            create(i.toString());
+    }
+
+    boolean getSameSchemaRelativeReferences(String scheme) {
+        return backwardCompatibleRelativeRefs.contains(scheme.toLowerCase());
+    }
+    
+    private String encoding = "utf-8";
+    String getEncoding() {
+        return encoding;
+    }
+    public void setEncoding(String enc) throws UnsupportedEncodingException {
+        // check enc is valid encoding.
+        "".getBytes(enc);
+        encoding = enc;
+    }
+    
+   
+    boolean asErrors[] = new boolean[]{
+            true,
+            true,
+            false,
+            true,
+            true,
+            true,
+            
+    };
+    boolean asWarnings[] = new boolean[]{
+      false,
+      false,
+      true,
+      false,
+      false,
+      false
+    };
+    
+    protected void setViolation(int ix, boolean e, boolean w){
+        if (e && w)
+            throw new IllegalArgumentException("xxxViolation(true,true) is not 
permitted.");
+        initializing();
+        asErrors[ix]=e;
+        asWarnings[ix]=w;
+        
+    }
+    
+    protected boolean getAsWarnings(int ix) {
+        return asWarnings[ix];
+    }
+
+    protected boolean getAsErrors(int ix) {
+        return asErrors[ix];
+    }
+//    boolean isException(int code) {
+//        return (errors & (1l<<code))!=0;
+//    }
+
+    private boolean initializing = true;
+private Set<String> backwardCompatibleRelativeRefs = new HashSet<>();
+    protected void initializing() {
+        if (!initializing)
+            throw new IllegalStateException("Cannot reinitialize IRIFactory 
after first use.");
+        
+    }
+    
+    @Override
+    public IRI create(String s) {
+        initializing = false;
+        return super.create(s);
+    }
+
+    public void setSameSchemeRelativeReferences(String scheme) {
+        if (scheme.equals("*"))
+          backwardCompatibleRelativeRefs  = new AbstractSet<String>(){
+
+            @Override
+            public int size() {
+                return Integer.MAX_VALUE;
+            }
+
+            @Override
+            public Iterator<String> iterator() {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public boolean add(String o) {
+                return false;
+            }
+
+            @Override
+            public boolean contains(Object o) {
+                return true;
+            }
+        };
+        else 
+            backwardCompatibleRelativeRefs.add(scheme.toLowerCase());
+    }
+
+    protected void useSpec(String name, boolean asErr) {
+        initializing();
+        Specification spec = Specification.get(name);
+        specs.add(spec);
+        for (int i=0; i<Force.SIZE; i++) {
+            if (asErrors[i] || (asWarnings[i] && asErr)) {
+                errors |= spec.getErrors(i);
+            }
+            if (asWarnings[i] ) {
+                warnings |= spec.getErrors(i);
+            }
+        }
+        prohibited |= spec.getProhibited();
+        required |= spec.getRequired();
+        warnings &= ~errors;
+        
+    }
+
+    public SchemeSpecificPart getScheme(String scheme, Parser parser) {
+        
+        scheme = scheme.toLowerCase();
+        SchemeSpecificPart p = schemes.get(scheme);
+        if (p!=null) {
+            p.usedBy(parser);
+            return p;
+        }
+        int dash = scheme.indexOf('-');
+        if (dash != -1) {
+            if (scheme.startsWith("x-")) {
+                p = noScheme();
+            } else {
+               if (nonIETFScheme==null)
+                       nonIETFScheme = new NoScheme() {
+                   @Override void usedBy(Parser pp) {
+                      pp.recordError(SCHEME,UNREGISTERED_NONIETF_SCHEME_TREE);
+                  }
+                };
+                p = nonIETFScheme;
+            }
+        } else if (Specification.schemes.containsKey(scheme)) {
+            SchemeSpecification spec = 
(SchemeSpecification)Specification.schemes.get(scheme);
+            p = new NoScheme(spec.port);
+        } else{
+               if (unregisteredScheme==null){
+                       unregisteredScheme = new NoScheme() {
+                           @Override void usedBy(Parser pp) {
+                           pp.recordError(SCHEME,UNREGISTERED_IANA_SCHEME);
+                       }
+                     };
+               }
+            p= unregisteredScheme;
+        }
+        p.usedBy(parser);
+//        System.err.println("Scheme: "+scheme);
+        if (schemes.size() < 1000)
+          schemes.put(scheme,p);
+        return p;
+    }
+    
+    private NoScheme unregisteredScheme=null;
+    private NoScheme nonIETFScheme=null;
+
+    public SchemeSpecificPart noScheme() {
+        return noScheme;
+    }
+    private class WithScheme extends SchemeSpecificPart
+    {
+        long zerrors;
+        long zwarnings;
+        int zrequired;
+        int zprohibited;
+        boolean inited = false;
+        final SchemeSpecification scheme;
+        private WithScheme(WithScheme ws) {
+            zerrors = ws.zerrors;
+            zwarnings = ws.zwarnings;
+            zprohibited = ws.zprohibited;
+            zrequired = ws.zrequired;
+            scheme = ws.scheme;
+        }
+        private WithScheme(SchemeSpecification spec, boolean asErr){
+            scheme = spec;
+            for (int i=0; i<Force.SIZE; i++) {
+                if (asErrors[i] || (asWarnings[i] && asErr)) {
+                    zerrors |= spec.getErrors(i);
+                }
+                if (asWarnings[i] ) {
+                    zwarnings |= spec.getErrors(i);
+                }
+            }
+            
+        }
+        @Override void usedBy(Parser parser) {
+            if (!inited) {
+                inited = true;
+                zerrors |= errors;
+                zwarnings |= warnings;
+                zwarnings &= ~zerrors;
+                zrequired = scheme.getRequired() | required;
+                zprohibited = scheme.getProhibited() | prohibited;
+            }
+            
+        }
+        @Override
+        public long getMask(boolean includeWarnings) {
+            return includeWarnings?(zerrors|zwarnings):zerrors;
+        }
+        @Override
+        public int getRequired() {
+            return zrequired;
+        }
+        @Override
+        public int getProhibited() {
+            return zprohibited;
+        }
+        @Override
+        public void analyse(Parser parser, int range) {
+            scheme.analyse(parser,range);
+        }
+        @Override
+        public int port() {
+            return scheme.port;
+        }
+        @Override
+        public boolean withScheme() {
+            return true;
+        }
+        
+    }
+    private class NoScheme extends SchemeSpecificPart {
+        
+        NoScheme() {
+            this(-1);
+        }
+        final private int port;
+        NoScheme(int i) {
+            port = i;
+        }
+        @Override
+        public long getMask(boolean includeWarnings) {
+            return IRIFactoryImpl.this.getMask(includeWarnings);
+        }
+        @Override
+        public int getRequired() {
+            return IRIFactoryImpl.this.getRequired();
+        }
+        @Override
+        public int getProhibited() {
+            return IRIFactoryImpl.this.getProhibited();
+        }
+        @Override
+        void usedBy(Parser parser) { /* nothing */ }
+        @Override
+        public void analyse(Parser parser, int range) {/* nothing */ }
+        @Override
+        public int port() {
+            return port;
+        }
+        @Override
+        public boolean withScheme() {
+            return false;
+        }
+        
+    }
+    
+    final private NoScheme noScheme = new NoScheme();
+    private int required = 0;
+    private int prohibited = 0;
+
+    public int getRequired() {
+        return required;
+    }
+
+    public int getProhibited() {
+        return prohibited ;
+    }
+
+    final private Map<String, SchemeSpecificPart> schemes = new HashMap<>();
+    
+    public void useSchemeSpecificRules(String scheme, boolean asErr)
+    {
+        if (scheme.equals("*"))
+        {
+            for ( String s : Specification.schemes.keySet() )
+            {
+                scheme = s;
+                if ( !schemes.containsKey( scheme ) )
+                {
+                    useSchemeSpecificRules( scheme, asErr );
+                }
+            }
+            return ;
+        }
+        scheme = scheme.toLowerCase() ;
+        SchemeSpecification spec = (SchemeSpecification) 
Specification.schemes.get(scheme) ;
+        if (spec == null)
+        {
+            schemes.put(scheme, noScheme) ;
+        } else
+        {
+            schemes.put(scheme, new WithScheme(spec, asErr)) ;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImpl.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImpl.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImpl.java
new file mode 100644
index 0000000..f2dc6bf
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImpl.java
@@ -0,0 +1,130 @@
+/*
+ * 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.jena.iri.impl;
+
+
+import org.apache.jena.iri.IRIComponents ;
+import org.apache.jena.iri.IRIFactory ;
+
+public class IRIImpl 
+  extends AbsIRIImpl
+implements IRIComponents {
+
+    final IRIFactoryImpl factory;
+    final String original;
+    final Parser parser;
+    Exception idnaException;
+
+    SchemeSpecificPart scheme;
+    
+    public IRIImpl(IRIFactory f) {
+        this(f,""
+//                ,NO_EXCEPTIONS
+                );
+    }
+
+//    IRIImpl(IRIFactoryImpl f, String s) {
+//        this(f,s,ALL_EXCEPTIONS);
+//        
+//    }
+    
+//    private IRIImpl(IRIFactory f, IRIImpl b, IRI r) {
+//        factory = f;
+//        
+//        // implement relative URI stuff ...
+//        
+//        if (b.original.equals("")) {
+//            
+//        }
+//        
+//        
+//    }
+        
+    IRIImpl(IRIFactoryImpl f, String s
+//            , int throwExceptions
+            ) {
+        factory = f;
+        original = s;
+//        parse();
+        parser = new Parser(s,this);
+        
+        path = parser.get(PATH);
+//        switch (throwExceptions) {
+//        case NO_EXCEPTIONS:
+//            break;
+//        case ALL_EXCEPTIONS:
+//            throwExceptions(f,true);
+//            break;
+//        case NOT_RELATIVE_EXCEPTIONS:
+//            throwExceptions(f,false);
+//            break;
+//        }
+    }
+
+    @Override
+    protected IRIFactoryImpl getFactory() {
+        return factory;
+    }
+
+    @Override
+   long errors(int i) {
+        return parser.errors(i);
+    }
+
+    @Override
+    boolean has(int component) {
+        return parser.has(component);
+    }
+
+    @Override
+    String get(int comp) {
+       return parser.get(comp);
+    }
+
+    @Override
+    String pathRemoveDots() {
+        if (dotsOK())
+          return path;
+        return removeDotSegments(path);
+    }
+
+    @Override
+    boolean dotsOK() {
+        return (errors(PATH)&(1l<<NON_INITIAL_DOT_SEGMENT))==0;
+    }
+    
+    @Override
+    public String toString() {
+        return original;
+    }
+
+    @Override
+    SchemeSpecificPart getSchemeSpec() {
+        return scheme;
+    }
+
+       @Override
+       Exception getIDNAException() {
+               return idnaException;
+       }
+
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImplException.java
----------------------------------------------------------------------
diff --git 
a/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImplException.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImplException.java
new file mode 100644
index 0000000..a0b9c40
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/IRIImplException.java
@@ -0,0 +1,44 @@
+/*
+ * 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.jena.iri.impl;
+
+import org.apache.jena.iri.IRIException ;
+import org.apache.jena.iri.Violation ;
+
+public class IRIImplException extends IRIException {
+
+    private static final long serialVersionUID = 1072420548744246731L;
+    private final Violation violation;
+
+    @Override
+    public Violation getViolation() {
+        return violation;
+    }
+    public IRIImplException(Violation e) {
+        super();
+        violation = e;
+    }
+
+    @Override
+    public String getMessage() {
+        return getViolation().getShortMessage();
+    }
+    
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/Lexer.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/Lexer.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/Lexer.java
new file mode 100644
index 0000000..db86a34
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/Lexer.java
@@ -0,0 +1,25 @@
+/*
+ * 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.jena.iri.impl;
+
+interface Lexer {
+
+    void analyse(Parser parser, int i);
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/36855e1b/jena-iri/src/main/java/org/apache/jena/iri/impl/LexerFragment.java
----------------------------------------------------------------------
diff --git a/jena-iri/src/main/java/org/apache/jena/iri/impl/LexerFragment.java 
b/jena-iri/src/main/java/org/apache/jena/iri/impl/LexerFragment.java
new file mode 100644
index 0000000..10124f9
--- /dev/null
+++ b/jena-iri/src/main/java/org/apache/jena/iri/impl/LexerFragment.java
@@ -0,0 +1,30 @@
+/*
+ * 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.jena.iri.impl;
+
+import java.io.Reader;
+
+
+class LexerFragment extends LexerQuery {
+
+    LexerFragment(Reader reader) {
+        super(reader);
+    }
+
+}

Reply via email to