Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Sa Dez 22 2007 01:35:21 CET
file stats: LOC: 464   Methods: 23
NCLOC: 255   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DefaultModuleAddress.java 36,1% 57,7% 60,9% 54%
coverage coverage
 1    /* $Id: DefaultModuleAddress.java,v 1.5 2007/12/21 23:33:46 m31 Exp $
 2    *
 3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
 4    *
 5    * Copyright 2000-2007, Michael Meyling <mime@qedeq.org>.
 6    *
 7    * "Hilbert II" is free software; you can redistribute
 8    * it and/or modify it under the terms of the GNU General Public
 9    * License as published by the Free Software Foundation; either
 10    * version 2 of the License, or (at your option) any later version.
 11    *
 12    * This program is distributed in the hope that it will be useful,
 13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15    * GNU General Public License for more details.
 16    */
 17   
 18    package org.qedeq.kernel.bo.load;
 19   
 20    import java.io.File;
 21    import java.io.IOException;
 22    import java.io.UnsupportedEncodingException;
 23    import java.net.MalformedURLException;
 24    import java.net.URL;
 25    import java.net.URLEncoder;
 26   
 27    import org.qedeq.kernel.base.module.LocationList;
 28    import org.qedeq.kernel.base.module.Specification;
 29    import org.qedeq.kernel.bo.module.ModuleAddress;
 30    import org.qedeq.kernel.bo.module.ModuleContext;
 31    import org.qedeq.kernel.bo.module.QedeqBo;
 32    import org.qedeq.kernel.trace.Trace;
 33    import org.qedeq.kernel.utility.IoUtility;
 34    import org.qedeq.kernel.utility.ReplaceUtility;
 35   
 36   
 37    /**
 38    * An object of this class represents an address for a QEDEQ module.
 39    *
 40    * @version $Revision: 1.5 $
 41    * @author Michael Meyling
 42    */
 43    public class DefaultModuleAddress implements ModuleAddress {
 44   
 45    /** Address. */
 46    private final String address;
 47   
 48    /** URL form of this address. */
 49    private final URL url;
 50   
 51    /** Header (including protocol, host, port, user) but without file path. */
 52    private final String header;
 53   
 54    /** Path (without protocol, host, port and file name). */
 55    private final String path;
 56   
 57    /** File name of QEDEQ module including <code>.xml</code>. */
 58    private final String fileName;
 59   
 60    /** Is module address relative? */
 61    private final boolean relativeAddress;
 62   
 63    /** Module name. That is file name without <code>.xml</code> */
 64    private final String name;
 65   
 66    /**
 67    * Constructor.
 68    *
 69    * @param u Address of module.
 70    * @param parent Address of parent module
 71    * @throws IOException if address is formally incorrect
 72    */
 73  0 public DefaultModuleAddress(final URL u, final DefaultModuleAddress parent)
 74    throws IOException {
 75   
 76  0 this(u.toExternalForm(), parent);
 77    }
 78   
 79    /**
 80    * Constructor.
 81    *
 82    * @param u Address of module.
 83    * @throws IOException if address is formally incorrect
 84    */
 85  30940 public DefaultModuleAddress(final URL u) throws IOException {
 86  30940 this(u.toExternalForm(), (DefaultModuleAddress) null);
 87    }
 88   
 89    /**
 90    * Constructor.
 91    *
 92    * @param file File path of module.
 93    * @throws IOException Address is formally incorrect
 94    */
 95  0 public DefaultModuleAddress(final File file)
 96    throws IOException {
 97  0 this(IoUtility.toUrl(file), (DefaultModuleAddress) null);
 98    }
 99   
 100    /**
 101    * Constructor.
 102    *
 103    * @param address Address of module.
 104    * @throws IOException Address is formally incorrect
 105    */
 106  0 public DefaultModuleAddress(final String address)
 107    throws IOException {
 108  0 this(address, (DefaultModuleAddress) null);
 109    }
 110   
 111    /**
 112    * Constructor.
 113    *
 114    * @param address address of module
 115    * @param parent address of parent module
 116    * @throws IOException if address is formally incorrect
 117    */
 118  33492 public DefaultModuleAddress(final String address, final DefaultModuleAddress parent)
 119    throws IOException {
 120   
 121  33492 final String method = "ModuleAddress(String, ModuleAddress)";
 122  33492 if (address == null) {
 123  0 throw new NullPointerException();
 124    }
 125  33492 URL urmel;
 126  33492 try {
 127  33492 if (parent != null) {
 128  2550 urmel = new URL(parent.url, address);
 129    } else {
 130  30942 urmel = new URL(address);
 131    }
 132    } catch (MalformedURLException e) {
 133  0 Trace.trace(this, method, "address=" + address);
 134  0 Trace.trace(this, method, "parent=" + parent);
 135  0 Trace.trace(this, method, e);
 136  0 try {
 137  0 final String newAddress = "file:" + address;
 138  0 if (parent != null) {
 139  0 urmel = new URL(parent.url, newAddress);
 140    } else {
 141  0 urmel = new URL(newAddress);
 142    }
 143    } catch (MalformedURLException ex) {
 144  0 throw e; // throw original exception
 145    }
 146    }
 147  33492 Trace.trace(this, method, "protocol=" + urmel.getProtocol());
 148  33489 url = urmel;
 149  33489 this.address = urmel.toExternalForm();
 150  33489 Trace.trace(this, method, "address=" + this.address);
 151    /*
 152    Trace.trace(this, METHOD, "url.getFile=" + this.url.getFile());
 153    Trace.trace(this, METHOD, "url.getPath=" + this.url.getPath());
 154    try {
 155    Trace.trace(this, METHOD, "URI File=" +
 156    new File(new URI(this.address)).getAbsoluteFile());
 157    } catch (URISyntaxException e1) {
 158    e1.printStackTrace();
 159    }
 160    */
 161  33489 final String p = urmel.getFile();
 162  33489 final int position = p.lastIndexOf("/");
 163  33489 if (position >= 0 && position + 1 < p.length()) {
 164  33489 this.path = p.substring(0, position) + "/";
 165  33489 this.fileName = p.substring(position + 1);
 166    } else {
 167  0 this.path = "";
 168  0 this.fileName = p;
 169    }
 170  33489 Trace.trace(this, method, "path=" + this.path);
 171  33489 Trace.trace(this, method, "fileName=" + this.fileName);
 172  33489 this.relativeAddress = !this.path.startsWith("/");
 173  33489 if (!this.fileName.endsWith(".xml")) {
 174  0 throw new IOException("file name doesn't end with \".xml\": "
 175    + this.fileName);
 176    }
 177  33489 final int positionBefore = this.fileName.lastIndexOf(".");
 178  33489 final String mname = this.fileName.substring(0, positionBefore);
 179  33489 this.name = mname;
 180  33489 final int positionPath
 181    = this.address.lastIndexOf(this.path + this.fileName);
 182  33489 if (positionPath < 0) {
 183  0 throw new IllegalArgumentException(
 184    "couldn't determine begin of file path: "
 185    + this.address);
 186    }
 187  33489 this.header = this.address.substring(0, positionPath);
 188    }
 189   
 190    /**
 191    * Get module address.
 192    *
 193    * @return module address
 194    */
 195  29460 public final String getAddress() {
 196  29460 return address;
 197    }
 198   
 199    /**
 200    * Get module address as {@link ModuleContext}. Creates a new object.
 201    *
 202    * @return Module address as {@link ModuleContext}.
 203    */
 204  0 public final ModuleContext createModuleContext() {
 205  0 return new ModuleContext(getURL());
 206    }
 207   
 208    /**
 209    * Get address header (including protocol, host, port, user)
 210    * but without file path.
 211    *
 212    * @return address header
 213    */
 214  0 public final String getHeader() {
 215  0 return header;
 216    }
 217   
 218    /**
 219    * Get address path (without protocol, host, port and file name).
 220    *
 221    * @return module path
 222    */
 223  25827 public final String getPath() {
 224  25827 return path;
 225    }
 226   
 227    /**
 228    * Get module file name.
 229    *
 230    * @return Module file name.
 231    */
 232  26733 public final String getFileName() {
 233  26733 return fileName;
 234    }
 235   
 236    /**
 237    * Get name of module (file name without <code>.xml</code>).
 238    *
 239    * @return Module name.
 240    */
 241  3417 public final String getName() {
 242  3417 return this.name;
 243    }
 244   
 245    /**
 246    * Get fully qualified URL of module.
 247    *
 248    * @return URL for QEDEQ module.
 249    */
 250  11030 public final URL getURL() {
 251  11030 return this.url;
 252    }
 253   
 254    /**
 255    * Was this module address created relatively?
 256    *
 257    * @return Relatively created?
 258    */
 259  0 public final boolean isRelativeAddress() {
 260  0 return this.relativeAddress;
 261    }
 262   
 263    /**
 264    * Is this a local QEDEQ file. That means the address starts with <code>file:</code>.
 265    *
 266    * @return Is the QEDEQ module a local file?
 267    */
 268  26479 public final boolean isFileAddress() {
 269  26479 return getAddress().indexOf("file:") == 0;
 270    }
 271   
 272    /**
 273    * Transform an URL address into a local file path.
 274    *
 275    * @param url transform this URL
 276    * @return result of transformation
 277    */
 278  467 public final String localizeInFileSystem(final URL url) {
 279  467 final String method = "localizeInFileSystem(URL)";
 280  467 Trace.traceStack(this, method); // FIXME mime 20071218: remove me
 281  467 Trace.param(this, method, "protocoll", url.getProtocol());
 282  467 Trace.param(this, method, "host", url.getHost());
 283  467 Trace.param(this, method, "port", url.getPort());
 284  467 Trace.param(this, method, "path", url.getPath());
 285  467 Trace.param(this, method, "file", url.getFile());
 286  467 StringBuffer file = new StringBuffer(url.getFile());
 287  467 ReplaceUtility.replace(file, "_", "__"); // remember all '_'
 288  467 ReplaceUtility.replace(file, "/", "_1"); // preserve all '/'
 289  467 String encoded = file.toString(); // fallback file name
 290  467 try {
 291  467 encoded = URLEncoder.encode(file.toString(), "UTF-8");
 292    } catch (UnsupportedEncodingException e) {
 293    // should not occur
 294  0 Trace.trace(DefaultModuleAddress.class, "localizeInFileSystem(String)", e);
 295    }
 296  467 file.setLength(0);
 297  467 file.append(encoded);
 298  467 ReplaceUtility.replace(file, "#", "##"); // escape all '#'
 299  467 ReplaceUtility.replace(file, "_1", "#"); // from '/' into '#'
 300  467 ReplaceUtility.replace(file, "__", "_"); // from '_' into '_'
 301  467 StringBuffer adr = new StringBuffer(url.toExternalForm());
 302  467 try {
 303  467 adr = new StringBuffer(new URL(url.getProtocol(), url.getHost(),
 304    url.getPort(), file.toString()).toExternalForm());
 305    } catch (MalformedURLException e) {
 306  0 Trace.fatal(this, "localizeInFileSystem(URL)", "unexpected", e);
 307  0 e.printStackTrace();
 308    }
 309    // escape characters:
 310  467 ReplaceUtility.replace(adr, "://", "_"); // before host
 311  467 ReplaceUtility.replace(adr, ":", "_"); // before protocol
 312  467 return adr.toString();
 313    }
 314   
 315    /**
 316    * Create relative address from <code>this</code> to <code>reference</code>.
 317    *
 318    * @param reference this should be the next location
 319    * @return relative (or if necessary absolute) address
 320    */
 321  0 public final String createRelativeAddress(
 322    final ModuleAddress reference) {
 323  0 return createRelativeAddress(getAddress(),
 324    reference.getAddress());
 325    }
 326   
 327  1093 public final String toString() {
 328  1093 return this.address;
 329    }
 330   
 331  17032 public final int hashCode() {
 332  17032 return this.address.hashCode();
 333    }
 334   
 335  15044 public final boolean equals(final Object object) {
 336  15044 if (object == null || !(object instanceof DefaultModuleAddress)) {
 337  2 return false;
 338    }
 339  15042 return address.equals(((DefaultModuleAddress) object).address);
 340    }
 341   
 342    /**
 343    * Get the file name of the specified module.
 344    *
 345    * TODO mime 20070326: is this function really neccessary?
 346    *
 347    * @param spec here are the (perhaps relative) addresses to
 348    * another module
 349    * @return file name of specified module
 350    */
 351  2543 public static final String getModuleFileName(final Specification spec) {
 352   
 353  2543 return spec.getName() + ".xml";
 354    }
 355   
 356    /**
 357    * Get all potential module addresses from a module specification.
 358    *
 359    * TODO mime 20070326: add context information (for error case)
 360    *
 361    * @param module Starting from that module (has an absolute
 362    * address).
 363    * @param spec Here are the (perhaps relative) addresses to
 364    * another module.
 365    * @return Array of absolute address strings.
 366    * @throws IOException One address is not correctly formed.
 367    */
 368  2543 public static final ModuleAddress[] getModulePaths(final QedeqBo module,
 369    final Specification spec) throws IOException {
 370   
 371  2543 final String fileNameEnd = getModuleFileName(spec);
 372  2543 final LocationList locations = spec.getLocationList();
 373  2543 final ModuleAddress[] result
 374    = new ModuleAddress[locations.size()];
 375  2543 for (int i = 0; i < locations.size(); i++) {
 376  2550 String fileName
 377    = locations.get(i).getLocation();
 378  2550 if (fileName.equals(".")) {
 379  2540 fileName = "";
 380  10 } else if (!fileName.endsWith("/")) {
 381  10 fileName += "/";
 382    }
 383  2550 fileName += fileNameEnd;
 384  2550 result[i] = new DefaultModuleAddress(fileName,
 385    (DefaultModuleAddress) module.getModuleAddress());
 386    }
 387  2542 return result;
 388    }
 389   
 390    /**
 391    * Create relative address from <code>orgin</code> to <code>next</code>.
 392    *
 393    * @param origin This is the original location (URL!).
 394    * @param next This should be the next location (URL!).
 395    * @return Relative (or if necessary absolute) address.
 396    */
 397  0 public static final String createRelativeAddress(final String origin,
 398    final String next) {
 399  0 if (origin.equals(next)) {
 400  0 return "";
 401    }
 402  0 try {
 403  0 final URL urlOrgin = new URL(origin);
 404  0 final URL urlNext = new URL(next);
 405   
 406  0 if (urlOrgin.getProtocol().equals(urlNext.getProtocol())
 407    && urlOrgin.getHost().equals(urlNext.getHost())
 408    && urlOrgin.getPort() == urlNext.getPort()) {
 409  0 final String org = urlOrgin.getFile();
 410  0 final String nex = urlNext.getFile();
 411  0 int i = -1; // position of next '/'
 412  0 int j = 0; // position of last '/'
 413  0 while (0 <= (i = org.indexOf("/", j))) {
 414  0 if (i >= 0 && nex.length() > i
 415    && org.substring(j, i).equals(
 416    nex.substring(j, i))) {
 417  0 j = i + 1;
 418    } else {
 419  0 break;
 420    }
 421    }
 422  0 if (j > 0) {
 423  0 i = j;
 424  0 StringBuffer result = new StringBuffer(nex.length());
 425  0 while (0 <= (i = org.indexOf("/", i))) {
 426  0 i++;
 427  0 result.append("../");
 428    }
 429  0 result.append(nex.substring(j));
 430  0 return result.toString();
 431    } else {
 432  0 return "/" + nex;
 433    }
 434    } else { // no relative address possible
 435  0 return urlNext.toString();
 436    }
 437    } catch (MalformedURLException e) {
 438  0 return next;
 439    }
 440   
 441    }
 442   
 443    /**
 444    * Get module address with new ending. E.g.: ".html" instead of ".qedeq".
 445    *
 446    * @param address The address of something (e.g.: a module).
 447    * @param newEnding This should be the new ending (e.g.: "html").
 448    * @return module address with substituted ending
 449    */
 450  0 public static final String newEnding(final String address,
 451    final String newEnding) {
 452  0 if (address.length() == 0) {
 453  0 return "";
 454    }
 455  0 final int i = address.lastIndexOf(".");
 456  0 if (i > 0) {
 457  0 return address.substring(0, i + 1) + newEnding;
 458    } else {
 459  0 return address + "." + newEnding;
 460    }
 461    }
 462   
 463    }
 464