/**
* Copyright 2009 Google Inc.
*
* 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.waveprotocol.wave.model.id;
import org.waveprotocol.wave.model.id.URIEncoderDecoder.EncodingException;
import org.waveprotocol.wave.model.id.URIEncoderDecoder.PercentEncoderDecoder;
/**
* This class is used to generate URI for ids.
*
* A wavelet name is expressible as a URI. The domain qualifying the wavelet id
* is used as the host part (since this is where the wavelet is hosted). The
* wave id is used as the first path element. If the wave domain does not match
* the wavelet domain the wave domain service provider id precedes the wave id
* token followed by a '!' delimeter. The wavelet id is a final path element.
*
* @see URIEncoderDecoder for percent escaping scheme.
*
*
* Examples:
*
* wave://wave.com/w+4ks3/conversation+root
*
* wave://tudalin.lv/profile+bob@tudalin.lv/profile+root
*
* wave://privatereply.com/wave.com!w+4Kl2/conversation+3sG7
*
*
*/
public class IdURIEncoderDecoder {
/** Used to encode parts of URI that needs to be escaped */
private final URIEncoderDecoder encoder;
/**
* @param percentEncoder An encoder able to percent encode strings.
*/
public IdURIEncoderDecoder(PercentEncoderDecoder percentEncoder) {
this.encoder = new URIEncoderDecoder(percentEncoder);
}
/**
* @param name The WaveletName to serialise. The domain name in WaveletId and WaveId
* is assumed to not have any funny characters that need escaping. The local parts (getId())
* of the wavelet id and wave id are assumed to have been "~" escaped where,
* "!", "~" are prefixed with "~". "+" is "~" escaped when not used as a separator
* token.
* @return URI representation of the WaveletName.
*
* @throws EncodingException This can happen if the values in name are not valid UTF-16.
*/
public String waveletNameToURI(WaveletName name) throws EncodingException {
return IdConstants.WAVE_URI_SCHEME + "://" + waveletNameToURIPath(name);
}
/**
* @param name The WaveletName to serialise. The domain name in WaveletId and WaveId
* is assumed to not have any funny characters that need escaping. The local parts (getId())
* of the wavelet id and wave id are assumed to have been "~" escaped where,
* "!", "~" are prefixed with "~". "+" is "~" escaped when not used as a separator
* token.
* @return path part of URI representation of the WaveletName.
*
* @throws EncodingException This can happen if the values in name are not valid UTF-16.
*/
public String waveletNameToURIPath(WaveletName name) throws EncodingException {
WaveId waveId = name.waveId;
WaveletId waveletId = name.waveletId;
String waveDomain = waveId.getDomain();
if (waveletId.getDomain().equals(waveDomain)) {
waveDomain = "";
} else {
waveDomain += "!";
}
return waveletId.getDomain() + "/" + waveDomain + encoder.encode(waveId.getId()) +
"/" + encoder.encode(waveletId.getId());
}
/**
* @param serialisedForm The serialised URI form of the wavelet name.
* @return The WaveletName that is deserialised
*
* @throws EncodingException if decoding fails. e.g. the hex values following percent in
* encodedValue cannot be interpreted as valid UTF-8 or if a percent is not followed
* by a hex value.
*/
public WaveletName uriToWaveletName(String serialisedForm) throws EncodingException {
String prefix = IdConstants.WAVE_URI_SCHEME + "://";
if (!serialisedForm.startsWith(prefix)) {
throw new IllegalArgumentException("Invalid scheme for the wavelet name URI: " +
serialisedForm);
}
return uriPathToWaveletName(serialisedForm.substring(prefix.length()));
}
/**
* @param serialisedForm The serialised URI path part only of the wavelet name.
* @return The WaveletName that is deserialised
* @throws EncodingException
*
* @throws EncodingException if decoding fails. e.g. the hex values following percent in
* encodedValue cannot be interpreted as valid UTF-8 or if a percent is not followed
* by a hex value.
*/
public WaveletName uriPathToWaveletName(String serialisedForm) throws EncodingException {
String[] parts = serialisedForm.split("/");
if (parts.length != 3) {
throw new IllegalArgumentException("Wavelet name URI path expected in the format of" +
" <wavelet domain>/[<wave domain>!]<wave id>/<wavelet id> but got: " +
serialisedForm);
}
WaveletId waveletId = WaveletId.ofLegacy(parts[0], encoder.decode(parts[2]));
String[] waveIdParts = SimplePrefixEscaper.DEFAULT_ESCAPER.splitWithoutUnescaping(
'!', parts[1]);
WaveId waveId;
if (waveIdParts.length == 1) {
waveId = WaveId.ofLegacy(waveletId.getDomain(), encoder.decode(waveIdParts[0]));
} else if (waveIdParts.length == 2) {
waveId = WaveId.ofLegacy(waveIdParts[0], encoder.decode(waveIdParts[1]));
} else {
throw new IllegalArgumentException("Wave id in URI path is invalid. Expected the format" +
" [<wave domain>!]<wave id> but got: " + parts[1]);
}
return WaveletName.of(waveId, waveletId);
}
}