/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl.header; import com.google.common.base.MoreObjects; import javax.ws.rs.ext.RuntimeDelegate; import java.util.Collections; import java.util.List; /** * Represents set of ranges provided by client in 'Range' header. * * @author andrew00x */ public final class Ranges { /** Represents one range from provided by client in HTTP header 'Range'. */ public static class Range { /** Start of range. */ private long start; /** End of range. */ private long end; Range(long start, long end) { this.start = start; this.end = end; } /** * Get start of range. This method may return -1 if start of range was not * provided in HTTP header, e.g. range was specified as '-100' (100 bytes * from the end of content). Range may be normalized by using method * {@link #validate(long)}. * * @return end of range */ public long getStart() { return start; } /** * Get end of range. This method may return -1 if end of range was not * provided in HTTP header, e.g. range was specified as '100-' (from byte * 100 end to the end of content). Range may be normalized by using method * {@link #validate(long)}. * * @return end of range */ public long getEnd() { return end; } /** * Normalize and validate range. The calling this method has next effect: * <ul> * <li>If {@code start} of range is -1 (range without start position) * {@code start} position should be set to * <code>length - (-1 * start)</code>, {@code end} will be set to * <code>length - 1</code></li> * <li>If {@code end} of range is -1 (range without end position) * {@code end} will be set to <code>length - 1</code></li> * <li>If {@code end} of range is greater then {@code length} * will be set to <code>length - 1</code></li> * </ul> * * @param length * total length of content * @return {@code true} if range is valid and {@code false} * otherwise */ public boolean validate(long length) { // Range set as bytes:-100 - take 100 bytes from the end. if (start < 0 && end == -1) { if ((-1 * start) >= length) { start = 0; } else { start = length + start; } end = length - 1; } else if (start >= 0 && end == -1) { // Range set as bytes:100- - take from 100 to the end. end = length - 1; } else if (end >= length) { // Fragment of bytes:100-200, end can be greater then content-length end = length - 1; } return (start >= 0) && (end >= 0) && (end >= start); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Range)) { return false; } Range range = (Range)o; return start == range.start && end == range.end; } @Override public int hashCode() { int hashcode = 8; hashcode = 31 * hashcode + (int)(start ^ (start >>> 32)); hashcode = 31 * hashcode + (int)(end ^ (end >>> 32)); return hashcode; } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .add("start", start) .add("end", end) .toString(); } } public static Ranges valueOf(String range) { return RuntimeDelegate.getInstance().createHeaderDelegate(Ranges.class).fromString(range); } private final List<Range> ranges; Ranges(List<Range> ranges) { this.ranges = Collections.unmodifiableList(ranges); } /** * Get unmodifiable set of ranges. * * @return set of ranges */ public List<Range> getRanges() { return ranges; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Ranges)) { return false; } return ranges.equals(((Ranges)o).ranges); } @Override public int hashCode() { int hashcode = 8; hashcode = 31 * hashcode + ranges.hashCode(); return hashcode; } }