/*
* 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 ResolvedRelativeIRI extends AbsIRIImpl {
final private AbsIRIImpl base;
final private AbsIRIImpl rel;
// these are all final, except that
// the constructor is factored so that
// they are set in a subroutine.
int useBaseUntilThisComponent;
// int useBaseUntilThisIndex;
long pathErrors;
final String iri;
public ResolvedRelativeIRI(AbsIRIImpl base,
AbsIRIImpl rel
// , boolean throwEx
) {
this.base = base;
this.rel = rel;
transformReferences();
iri = createIRIString();
allErrors = 0l;
for (int i=0; i<Parser.fields.length;i++)
allErrors |= errors(Parser.fields[i]);
// if (throwEx)
// throwExceptions(getFactory(),true);
}
/**
* Algorithm transform references from 5.2.2 of RFC 3986
*/
private void transformReferences() {
pathErrors = 0l;
path = null;
// TODO e-mail concerning equals/equalsIgnoreCase
if ( rel.has(SCHEME)
&& (!getFactory().getSameSchemaRelativeReferences(rel.getScheme()) ||
!base.has(SCHEME) ||
!rel.getScheme().equalsIgnoreCase(base.getScheme())
)
) {
useBaseUntilThisComponent = SCHEME;
} else {
if (rel.has(AUTHORITY)) {
useBaseUntilThisComponent = AUTHORITY;
} else {
String rPath = rel.getRawPath();
if (rPath.equals("")) {
if (rel.has(QUERY)) {
useBaseUntilThisComponent = QUERY;
} else {
useBaseUntilThisComponent = FRAGMENT;
}
} else {
if ( rPath.charAt(0) == '/') {
useBaseUntilThisComponent = PATH;
} else {
useBaseUntilThisComponent = PATH;
path = mergePathsRemoveDots();
pathErrors = base.errors(PATH);
}
}
}
}
if (useBaseUntilThisComponent <= PATH) {
pathErrors |= rel.errors(PATH);
if (path==null ) {
path = rel.pathRemoveDots();
}
} else {
pathErrors |= base.errors(PATH);
path = base.getRawPath();
}
// useBaseUntilThisIndex = Parser.invFields[useBaseUntilThisComponent];
// if ( rel.has(SCHEME)
// && getFactory().getSameSchemaRelativeReferences(rel.getScheme())
// &&
// base.has(SCHEME) &&
// rel.getScheme().equalsIgnoreCase(base.getScheme()) )
//
// {
// System.err.println(base.toString()+" "+rel.toString()+" "+createIRIString());
// }
}
private String createIRIString() {
StringBuilder iriBuf = new StringBuilder();
if (has(SCHEME)){
iriBuf.append(getScheme());
iriBuf.append(':');
}
if (has(AUTHORITY)) {
iriBuf.append("//");
iriBuf.append(getRawAuthority());
}
iriBuf.append(getRawPath());
if (has(QUERY)) {
iriBuf.append('?');
iriBuf.append(getRawQuery());
}
if (has(FRAGMENT)) {
iriBuf.append('#');
iriBuf.append(getRawFragment());
}
return iriBuf.toString();
}
private String mergePathsRemoveDots() {
if (base.has(AUTHORITY)
&& base.getRawPath().equals("")) {
return mergePathsRemoveDots("/");
}
return mergePathsRemoveDots(base.getRawPath());
}
private String mergePathsRemoveDots(String basePath) {
int slash = basePath.lastIndexOf('/');
StringBuffer output = new StringBuffer();
if (slash!=-1)
output.append(basePath.substring(0,slash+1));
if (base.dotsOK()&&rel.dotsOK())
{
String relPath = rel.getRawPath();
if (relPath.startsWith("./"))
relPath = relPath.substring(2);
while (relPath.startsWith("../"))
{
relPath = relPath.substring(3);
removeLastSeqment2(output);
}
if (relPath.equals("..") )
{
relPath = "";
removeLastSeqment2(output);
}
if (relPath.equals(".") )
relPath = "";
output.append(relPath);
return output.toString();
}
output.append(rel.getRawPath());
return removeDotSegments(output.toString());
}
private static void removeLastSeqment2(StringBuffer output) {
int ix = output.length()-1;
if (ix<=0)
return;
while (ix>0) {
ix--;
if (output.charAt(ix)=='/') {
ix++;
break;
}
}
output.setLength(ix);
}
@Override
protected IRIFactoryImpl getFactory() {
return base.getFactory();
}
@Override
long errors(int field) {
return
field==PATH?pathErrors:
field<useBaseUntilThisComponent?base.errors(field):
rel.errors(field);
}
@Override
boolean has(int field) {
return field==PATH||(
field<useBaseUntilThisComponent?base.has(field):
rel.has(field) );
}
@Override
String get(int field) {
return field==PATH?path:
field<useBaseUntilThisComponent?base.get(field):
rel.get(field);
}
@Override
public String toString() {
return iri;
}
@Override
String pathRemoveDots() {
return useBaseUntilThisComponent > PATH?
base.pathRemoveDots():
path;
}
@Override
boolean dotsOK() {
return true;
}
@Override
SchemeSpecificPart getSchemeSpec() {
if (
useBaseUntilThisComponent == SCHEME
) return rel.getSchemeSpec();
return base.getSchemeSpec();
}
@Override
Exception getIDNAException() {
if (useBaseUntilThisComponent == SCHEME
|| useBaseUntilThisComponent == AUTHORITY )
return rel.getIDNAException();
return base.getIDNAException();
}
}