blob: d47a506eb9a2bfce37aa370f1fd29568b78382d9 [file] [log] [blame]
/*
* Copyright (c) 2010-2012, 2015 Eike Stepper (Berlin, Germany) and others.
* 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.util;
import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.net4j.util.security.IUserManager;
import org.eclipse.emf.common.util.URI;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import java.util.Map;
import java.util.Map.Entry;
/**
* Represents a CDO-specific {@link URI} in connection-aware format.
* <p>
* CDO URIs are in one of two different formats, either canonical or connection-aware. The connection-aware format is:
*
* <blockquote><b>cdo.net4j.</b> <i>ConnectorType</i> <b>://</b> [<i>User</i> [<b>:</b> <i>Password</i>] <b>@</b>]
* <i>ConnectorSpecificAuthority</i> <b>/</b> <i>RepositoryName</i> <b>/</b> <i>ResourcePath</i> [<b>?</b> <i>Param</i><b>=</b><i>Value</i>
* (<b>&</b> <i>Param</i><b>=</b><i>Value</i>)*]</blockquote>
*
* The non-terminals being:
* <p>
* <ul>
* <li><i>ConnectorType</i>: one of <b>tcp</b> | <b>ssl</b> | <b>jvm</b> | <b>http</b>
* <li><i>User/Password</i>: to be provided if the repository is configured with an
* {@link IUserManager} and, hence, triggers authentication on the client. Note: the
* password may be stored in resources in clear text!
* <li><i>ConnectorSpecificAuthority</i>: examples are
* <ul>
* <li><i>Host</i> [<b>:</b> <i>Port</i>] (if <i>ConnectorType</i> is <b>tcp</b>)
* <li><i>AcceptorName</i> (if <i>ConnectorType</i> is <b>jvm</b>)
* </ul>
* <li><i>RepositoryName</i>: the {@link CDOCommonRepository#getName() name} of the repository (not the {@link CDOCommonRepository#getUUID() UUID}!).
* <li><i>ResourcePath</i>: the full path of the {@link CDOResource resource} within the repository, segments separated by slashes, no leading slash.
* <li><i>Param</i>: one of the following
* <ul>
* <li><b>branch</b>: the value must be a {@link CDOBranch#getPathName() branch path}, the full path of the branch in the branch tree, segments separated by slashes, no leading slash, defaults to <b>MAIN</b>.
* <li><b>time</b>: the value must be the time at which the resource is supposed to be valid, parseable by SimpleDateFormat. The special value <b>HEAD</b> indicates a floating view/transaction that always shows the latest state in the chosen branch, the default if no <i>Time</i> parameter is specified.
* <li><b>transactional</b>: a boolean value. The value <b>true</b> forces a the resource to be opened in a transaction rather than in a read-only view. This can not be combined with a <i>Time</i> other than <b>HEAD</b>.
* <li><b>prefetch</b>: a boolean value. The value <b>true</b> attempts to load all objects contained by the resource in a single server-round trip and cache the results.
* </ul>
* </ul>
* <p>
* Note: With the current design and implementation of connection-aware URI
* (mainly CDONet4jViewProvider) it is still unclear when and how the allocated
* "resources" (aka IConnector, CDOSession, CDOView, etc) are supposed to be freed!
* <p>
* For a description of the canonical URI format refer to {@link CDOURIUtil}.
*
* @author Eike Stepper
* @since 4.0
*/
public final class CDOURIData
{
public static final String BRANCH_PARAMETER = "branch";
public static final String TIME_PARAMETER = "time";
/**
* @since 4.1
*/
public static final String VIEW_ID_PARAMETER = "view";
public static final String TRANSACTIONAL_PARAMETER = "transactional";
private String scheme;
private String userName;
private String passWord;
private String authority;
private String repositoryName;
private IPath resourcePath;
private IPath branchPath = new Path(CDOBranch.MAIN_BRANCH_NAME);
private long timeStamp = CDOBranchPoint.UNSPECIFIED_DATE;
private String viewID;
private boolean transactional;
private Map<String, String> extraParameters;
public CDOURIData()
{
}
public CDOURIData(String uri) throws InvalidURIException
{
this(URI.createURI(uri));
}
public CDOURIData(URI uri) throws InvalidURIException
{
try
{
scheme = uri.scheme();
authority = uri.authority();
String userInfo = uri.userInfo();
if (userInfo != null)
{
authority = authority.substring(userInfo.length() + 1);
int colon = userInfo.indexOf(':');
if (colon != -1)
{
userName = userInfo.substring(0, colon);
passWord = userInfo.substring(colon + 1);
}
else
{
userName = userInfo;
}
}
IPath path = new Path(uri.path()).makeAbsolute();
repositoryName = path.segment(0);
resourcePath = path.removeFirstSegments(1);
if (resourcePath == null || resourcePath.isEmpty())
{
resourcePath = new Path(CDOURIUtil.SEGMENT_SEPARATOR);
}
String query = uri.query();
if (query != null && query.length() != 0)
{
Map<String, String> parameters = CDOURIUtil.getParameters(query);
String branch = parameters.remove(BRANCH_PARAMETER);
if (branch != null)
{
branchPath = new Path(branch).makeRelative();
}
String time = parameters.remove(TIME_PARAMETER);
if (time != null)
{
if (!"HEAD".equalsIgnoreCase(time))
{
timeStamp = Long.parseLong(time);
}
}
viewID = parameters.remove(VIEW_ID_PARAMETER);
String transactional = parameters.remove(TRANSACTIONAL_PARAMETER);
if (transactional != null)
{
this.transactional = Boolean.parseBoolean(transactional);
}
if (!parameters.isEmpty())
{
extraParameters = parameters;
}
}
if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE && transactional)
{
throw new IllegalArgumentException("Only HEAD can be transactional");
}
}
catch (Throwable t)
{
throw new InvalidURIException(uri, t);
}
// branchPath = Path.EMPTY.makeAbsolute();
// timeStamp = CDOBranchPoint.UNSPECIFIED_DATE;
//
// while (resourcePath.segmentCount() != 0)
// {
// String segment = resourcePath.segment(0);
// resourcePath = resourcePath.removeFirstSegments(1);
//
// if (segment.startsWith("@"))
// {
// if (segment.length() != 1)
// {
// if (!segment.equals("@HEAD"))
// {
// timeStamp = Long.parseLong(segment.substring(1));
// }
// }
//
// break;
// }
//
// branchPath = branchPath.append(segment);
// }
//
// int segments = branchPath.segmentCount();
// if (segments == 0 || segments == 1 && !branchPath.segment(0).equals(CDOBranch.MAIN_BRANCH_NAME))
// {
// branchPath = new Path(CDOBranch.MAIN_BRANCH_NAME).append(branchPath);
// }
}
public String getScheme()
{
return scheme;
}
public void setScheme(String scheme)
{
this.scheme = scheme;
}
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getPassWord()
{
return passWord;
}
public void setPassWord(String passWord)
{
this.passWord = passWord;
}
public String getAuthority()
{
return authority;
}
public void setAuthority(String authority)
{
this.authority = authority;
}
public String getRepositoryName()
{
return repositoryName;
}
public void setRepositoryName(String repositoryName)
{
this.repositoryName = repositoryName;
}
public IPath getResourcePath()
{
return resourcePath;
}
public void setResourcePath(IPath resourcePath)
{
this.resourcePath = resourcePath;
}
public IPath getBranchPath()
{
return branchPath;
}
public void setBranchPath(IPath branchPath)
{
this.branchPath = branchPath;
}
public long getTimeStamp()
{
return timeStamp;
}
public void setTimeStamp(long timeStamp)
{
this.timeStamp = timeStamp;
}
/**
* @since 4.1
*/
public String getViewID()
{
return viewID;
}
/**
* @since 4.1
*/
public void setViewID(String viewID)
{
this.viewID = viewID;
}
public boolean isTransactional()
{
return transactional;
}
public void setTransactional(boolean transactional)
{
this.transactional = transactional;
}
/**
* @since 4.1
*/
public Map<String, String> getExtraParameters()
{
return extraParameters;
}
/**
* @since 4.4
*/
public void setExtraParameters(Map<String, String> extraParameters)
{
this.extraParameters = extraParameters;
}
public URI toURI()
{
return URI.createURI(toString());
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append(scheme);
builder.append("://");
if (userName != null)
{
builder.append(userName);
if (passWord != null)
{
builder.append(":");
builder.append(passWord);
}
builder.append("@");
}
builder.append(authority);
builder.append("/");
builder.append(repositoryName);
if (resourcePath != null)
{
builder.append("/");
builder.append(resourcePath);
}
int params = 0;
if (branchPath != null && !branchPath.equals(new Path(CDOBranch.MAIN_BRANCH_NAME)))
{
builder.append(params++ == 0 ? "?" : "&");
builder.append(BRANCH_PARAMETER);
builder.append("=");
builder.append(branchPath.toPortableString());
}
if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE)
{
builder.append(params++ == 0 ? "?" : "&");
builder.append(TIME_PARAMETER);
builder.append("=");
builder.append(timeStamp);
}
if (viewID != null)
{
builder.append(params++ == 0 ? "?" : "&");
builder.append(VIEW_ID_PARAMETER);
builder.append("=");
builder.append(viewID);
}
if (transactional)
{
builder.append(params++ == 0 ? "?" : "&");
builder.append(TRANSACTIONAL_PARAMETER);
builder.append("=");
builder.append(transactional);
}
if (extraParameters != null)
{
for (Entry<String, String> entry : extraParameters.entrySet())
{
builder.append(params++ == 0 ? "?" : "&");
builder.append(entry.getKey());
builder.append("=");
builder.append(entry.getValue());
}
}
return builder.toString();
}
}