001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.http.commons.domain; 007 008import static java.lang.Long.parseLong; 009import static java.util.regex.Pattern.compile; 010 011import java.util.regex.Matcher; 012import java.util.regex.Pattern; 013 014/** 015 * Range header parsing logic 016 * 017 * @author awoods 018 */ 019public class Range { 020 021 private final long start; 022 023 private final long end; 024 025 private static final Pattern rangePattern = 026 compile("^bytes\\s*=\\s*(\\d*)\\s*-\\s*(\\d*)"); 027 028 /** 029 * Unbounded Range 030 */ 031 private Range() { 032 this(0, -1); 033 } 034 035 /** 036 * Left-bounded range 037 * @param start the start 038 */ 039 public Range(final long start) { 040 this(start, -1L); 041 } 042 043 /** 044 * Left and right bounded range 045 * @param start the start 046 * @param end the end 047 */ 048 private Range(final long start, final long end) { 049 this.start = start; 050 this.end = end; 051 } 052 053 /** 054 * Does this range actually impose limits 055 * @return true if the range imposes limits 056 */ 057 public boolean hasRange() { 058 return !(start == 0 && end == -1); 059 } 060 061 /** 062 * Length contained in the range 063 * @return length of the range 064 */ 065 public long size() { 066 if (end == -1) { 067 return -1; 068 } 069 return end - start + 1; 070 } 071 072 /** 073 * Start of the range 074 * @return start of the range 075 */ 076 public long start() { 077 return start; 078 } 079 080 /** 081 * End of the range 082 * @return end of the range 083 */ 084 public long end() { 085 return end; 086 } 087 088 /** 089 * Convert an HTTP Range header to a Range object 090 * @param source the source 091 * @return range object 092 */ 093 public static Range convert(final String source) { 094 095 final Matcher matcher = rangePattern.matcher(source); 096 097 if (!matcher.matches()) { 098 return new Range(); 099 } 100 101 final String from = matcher.group(1); 102 final String to = matcher.group(2); 103 104 final long start; 105 106 if (from.equals("")) { 107 start = 0; 108 } else { 109 start = parseLong(from); 110 } 111 112 final long end; 113 if (to.equals("")) { 114 end = -1; 115 } else { 116 end = parseLong(to); 117 } 118 119 return new Range(start, end); 120 } 121}