merge with branch 1.x

This commit is contained in:
Sebastian Sdorra
2017-01-12 19:50:39 +01:00
250 changed files with 16399 additions and 1573 deletions

View File

@@ -96,7 +96,7 @@ public class BasicContextProvider implements SCMContextProvider
version = loadVersion();
stage = loadProjectStage();
}
catch (Throwable ex)
catch (Exception ex)
{
this.startupError = ex;

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm;
import sonia.scm.event.HandlerEvent;
/**
* Extension to the {@link ModificationHandlerEvent}.
*
* @param <T> type of changed item
*
* @author Sebastian Sdorra
* @since 1.48
*/
public interface ModificationHandlerEvent<T> extends HandlerEvent<T>
{
/**
* Returns item, before it was modified.
*
* @return item before modification
*/
public T getItemBeforeModification();
}

View File

@@ -134,6 +134,7 @@ public class ScmConfiguration
this.skipFailedAuthenticators = other.skipFailedAuthenticators;
this.loginAttemptLimit = other.loginAttemptLimit;
this.loginAttemptLimitTimeout = other.loginAttemptLimitTimeout;
this.enabledXsrfProtection = other.enabledXsrfProtection;
}
//~--- get methods ----------------------------------------------------------
@@ -325,6 +326,19 @@ public class ScmConfiguration
return disableGroupingGrid;
}
/**
* Returns {@code true} if the cookie xsrf protection is enabled.
*
* @see <a href="https://goo.gl/s67xO3">Issue 793</a>
* @return {@code true} if the cookie xsrf protection is enabled
*
* @since 1.47
*/
public boolean isEnabledXsrfProtection()
{
return enabledXsrfProtection;
}
/**
* Returns true if proxy is enabled.
*
@@ -611,6 +625,19 @@ public class ScmConfiguration
this.skipFailedAuthenticators = skipFailedAuthenticators;
}
/**
* Set {@code true} to enable xsrf cookie protection.
*
* @param enabledXsrfProtection {@code true} to enable xsrf protection
* @see <a href="https://goo.gl/s67xO3">Issue 793</a>
*
* @since 1.47
*/
public void setEnabledXsrfProtection(boolean enabledXsrfProtection)
{
this.enabledXsrfProtection = enabledXsrfProtection;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@@ -700,4 +727,12 @@ public class ScmConfiguration
/** Field description */
private boolean anonymousAccessEnabled = false;
/**
* Enables xsrf cookie protection.
*
* @since 1.47
*/
@XmlElement(name = "xsrf-protection")
private boolean enabledXsrfProtection = false;
}

View File

@@ -48,18 +48,18 @@ public abstract class AbstractGroupManager implements GroupManager
{
/**
* Send a {@link GroupEvent} to the {@link ScmEventBus}.
* Creates a {@link GroupEvent} and send it to the {@link ScmEventBus}.
*
* @param event type of change event
* @param group group that has changed
*/
protected void fireEvent(HandlerEventType event, Group group)
{
ScmEventBus.getInstance().post(new GroupEvent(event, group));
fireEvent(new GroupEvent(event, group));
}
/**
* Send a {@link GroupEvent} to the {@link ScmEventBus}.
* Creates a {@link GroupModificationEvent} and send it to the {@link ScmEventBus}.
*
* @param event type of change event
* @param group group that has changed
@@ -67,6 +67,16 @@ public abstract class AbstractGroupManager implements GroupManager
*/
protected void fireEvent(HandlerEventType event, Group group, Group oldGroup)
{
ScmEventBus.getInstance().post(new GroupEvent(event, group, oldGroup));
fireEvent(new GroupModificationEvent(event, group, oldGroup));
}
/**
* Sends a {@link GroupEvent} to the {@link ScmEventBus}.
*
* @param event group event
*/
protected void fireEvent(GroupEvent event)
{
ScmEventBus.getInstance().post(event);
}
}

View File

@@ -47,7 +47,7 @@ import sonia.scm.event.Event;
* @since 1.23
*/
@Event
public final class GroupEvent extends AbstractHandlerEvent<Group>
public class GroupEvent extends AbstractHandlerEvent<Group>
{
/**

View File

@@ -0,0 +1,66 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.group;
import sonia.scm.HandlerEventType;
import sonia.scm.ModificationHandlerEvent;
/**
* Event which is fired whenever a group is modified.
*
* @author Sebastian Sdorra
* @since 1.48
*/
public class GroupModificationEvent extends GroupEvent implements ModificationHandlerEvent<Group>
{
private final Group itemBeforeModification;
/**
* Constructs a new {@link GroupModificationEvent}.
*
* @param eventType type of event
* @param item changed group
* @param itemBeforeModification changed group before it was modified
*/
public GroupModificationEvent(HandlerEventType eventType, Group item, Group itemBeforeModification)
{
super(eventType, item);
this.itemBeforeModification = itemBeforeModification;
}
@Override
public Group getItemBeforeModification()
{
return itemBeforeModification;
}
}

View File

@@ -48,7 +48,10 @@ import java.util.Map;
* @apiviz.landmark
* @apiviz.uses sonia.scm.net.HttpRequest
* @apiviz.uses sonia.scm.net.HttpResponse
*
* @deprecated use {@link sonia.scm.net.ahc.AdvancedHttpClient} instead.
*/
@Deprecated
public interface HttpClient
{

View File

@@ -51,7 +51,11 @@ import java.util.Map;
*
* @author Sebastian Sdorra
* @since 1.9
*
* @deprecated use {@link sonia.scm.net.ahc.AdvancedHttpRequest} or
* {@link sonia.scm.net.ahc.AdvancedHttpRequestWithBody} instead.
*/
@Deprecated
public class HttpRequest
{

View File

@@ -41,12 +41,16 @@ import java.io.InputStream;
import java.util.List;
import java.util.Map;
import sonia.scm.net.ahc.AdvancedHttpResponse;
/**
* Response of a {@link HttpRequest} execute by the {@link HttpClient}.
*
* @author Sebastian Sdorra
*
* @deprecated use {@link AdvancedHttpResponse} instead
*/
@Deprecated
public interface HttpResponse extends Closeable
{

View File

@@ -0,0 +1,202 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
/**
* Advanced client for http operations. The {@link AdvancedHttpClient} replaces
* the much more simpler implementation {@link sonia.scm.net.HttpClient}. The
* {@link AdvancedHttpClient} offers a fluid interface for handling most common
* http operations. The {@link AdvancedHttpClient} can be injected by the
* default injection mechanism of SCM-Manager.
* <p>&nbsp;</p>
* <b>Http GET example:</b>
*
* <pre><code>
* AdvancedHttpResponse response = client.get("https://www.scm-manager.org")
* .decodeGZip(true)
* .request();
*
* System.out.println(response.contentAsString());
* </code></pre>
*
* <p>&nbsp;</p>
* <b>Http POST example:</b>
*
* <pre><code>
* AdvancedHttpResponse response = client.post("https://www.scm-manager.org")
* .formContent()
* .field("firstname", "Tricia")
* .field("lastname", "McMillan")
* .build()
* .request();
*
* if (response.isSuccessful()){
* System.out.println("success");
* }
* </code></pre>
*
* @author Sebastian Sdorra
* @since 1.46
*
* @apiviz.landmark
*/
public abstract class AdvancedHttpClient
{
/**
* Creates a {@link ContentTransformer} for the given Content-Type.
*
* @param type object type
* @param contentType content-type
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return {@link ContentTransformer}
*/
protected abstract ContentTransformer createTransformer(Class<?> type,
String contentType);
/**
* Executes the given request and returns the http response. Implementation
* have to check, if the instance if from type
* {@link AdvancedHttpRequestWithBody} in order to handle request contents.
*
*
* @param request request to execute
*
* @return http response
*
* @throws IOException
*/
protected abstract AdvancedHttpResponse request(BaseHttpRequest<?> request)
throws IOException;
/**
* Returns a builder for a DELETE request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody delete(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.DELETE, url);
}
/**
* Returns a builder for a HEAD request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequest head(String url)
{
return new AdvancedHttpRequest(this, HttpMethod.HEAD, url);
}
/**
* Returns a request builder with a custom method. <strong>Note:</strong> not
* every method is supported by the underlying implementation of the http
* client.
*
*
* @param method http method
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody method(String method, String url)
{
return new AdvancedHttpRequestWithBody(this, method, url);
}
/**
* Returns a builder for a OPTIONS request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody options(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.OPTIONS, url);
}
/**
* Returns a builder for a POST request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody post(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.POST, url);
}
/**
* Returns a builder for a PUT request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequestWithBody put(String url)
{
return new AdvancedHttpRequestWithBody(this, HttpMethod.PUT, url);
}
//~--- get methods ----------------------------------------------------------
/**
* Returns a builder for a GET request.
*
*
* @param url request url
*
* @return request builder
*/
public AdvancedHttpRequest get(String url)
{
return new AdvancedHttpRequest(this, HttpMethod.GET, url);
}
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
/**
* An http request without {@link Content} for example a GET or HEAD request.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class AdvancedHttpRequest extends BaseHttpRequest<AdvancedHttpRequest>
{
/**
* Constructs a new {@link AdvancedHttpRequest}
*
*
* @param client
* @param method
* @param url
*/
AdvancedHttpRequest(AdvancedHttpClient client, String method,
String url)
{
super(client, method, url);
}
//~--- methods --------------------------------------------------------------
/**
* Returns {@code this}.
*
*
* @return {@code this}
*/
@Override
protected AdvancedHttpRequest self()
{
return this;
}
}

View File

@@ -0,0 +1,271 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.io.ByteSource;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.nio.charset.Charset;
/**
* Http request with body.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class AdvancedHttpRequestWithBody
extends BaseHttpRequest<AdvancedHttpRequestWithBody>
{
/**
* Constructs a new {@link AdvancedHttpRequestWithBody}.
*
*
* @param client http client
* @param method http method
* @param url url
*/
AdvancedHttpRequestWithBody(AdvancedHttpClient client, String method,
String url)
{
super(client, method, url);
}
//~--- methods --------------------------------------------------------------
/**
* Sets the content length for the request.
*
*
* @param length content length
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody contentLength(long length)
{
return header("Content-Length", String.valueOf(length));
}
/**
* Sets the content type for the request.
*
*
* @param contentType content type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody contentType(String contentType)
{
return header("Content-Type", contentType);
}
/**
* Sets the content of the file as request content.
*
*
* @param file file
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody fileContent(File file)
{
this.content = new FileContent(file);
return this;
}
/**
* Returns a {@link FormContentBuilder}. The builder can be used to add form
* parameters as content for the request. <strong>Note:</strong> you have to
* call {@link FormContentBuilder#build()} in order to apply the form content
* to the request.
*
* @return form content builder
*/
public FormContentBuilder formContent()
{
return new FormContentBuilder(this);
}
/**
* Transforms the given object to a xml string and set this string as request
* content.
*
* @param object object to transform
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the json content-type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody jsonContent(Object object)
{
return transformedContent(ContentType.JSON, object);
}
/**
* Sets the raw data as request content.
*
*
* @param data raw data
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody rawContent(byte[] data)
{
this.content = new RawContent(data);
return this;
}
/**
* Sets the raw data as request content.
*
*
* @param source byte source
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody rawContent(ByteSource source)
{
this.content = new ByteSourceContent(source);
return this;
}
/**
* Sets the string as request content.
*
*
* @param content string content
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody stringContent(String content)
{
return stringContent(content, Charsets.UTF_8);
}
/**
* Sets the string as request content.
*
*
* @param content string content
* @param charset charset of content
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody stringContent(String content,
Charset charset)
{
this.content = new StringContent(content, charset);
return this;
}
/**
* Transforms the given object to a string and set this string as request
* content. The content-type is used to pick the right
* {@link ContentTransformer}. The method will throw an exception if no
* {@link ContentTransformer} for the content-type could be found.
*
* @param contentType content-type
* @param object object to transform
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the given content-type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody transformedContent(String contentType,
Object object)
{
ContentTransformer transformer =
client.createTransformer(object.getClass(), contentType);
ByteSource value = transformer.marshall(object);
contentType(contentType);
return rawContent(value);
}
/**
* Transforms the given object to a xml string and set this string as request
* content.
*
* @param object object to transform
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the xml content-type
*
* @return {@code this}
*/
public AdvancedHttpRequestWithBody xmlContent(Object object)
{
return transformedContent(ContentType.XML, object);
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the content or the request.
*
*
* @return request content
*/
public Content getContent()
{
return content;
}
//~--- methods --------------------------------------------------------------
/**
* Returns {@code this}.
*
*
* @return {@code this}
*/
@Override
protected AdvancedHttpRequestWithBody self()
{
return this;
}
//~--- fields ---------------------------------------------------------------
/** request content */
private Content content;
}

View File

@@ -0,0 +1,312 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
//~--- JDK imports ------------------------------------------------------------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
/**
* Http response. The response of a {@link AdvancedHttpRequest} or
* {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public abstract class AdvancedHttpResponse
{
/**
* Returns the response content as byte source.
*
*
* @return response content as byte source
* @throws IOException
*/
public abstract ByteSource contentAsByteSource() throws IOException;
//~--- get methods ----------------------------------------------------------
/**
* Returns the response headers.
*
*
* @return response headers
*/
public abstract Multimap<String, String> getHeaders();
/**
* Returns the status code of the response.
*
*
* @return status code
*/
public abstract int getStatus();
/**
* Returns the status text of the response.
*
*
* @return status text
*/
public abstract String getStatusText();
//~--- methods --------------------------------------------------------------
/**
* Creates a {@link ContentTransformer} for the given Content-Type.
*
* @param type object type
* @param contentType content-type
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return {@link ContentTransformer}
*/
protected abstract ContentTransformer createTransformer(Class<?> type,
String contentType);
/**
* Returns the content of the response as byte array.
*
*
* @return content as byte array
*
* @throws IOException
*/
public byte[] content() throws IOException
{
ByteSource content = contentAsByteSource();
byte[] data = null;
if (content != null)
{
data = content.read();
}
return data;
}
/**
* Returns a reader for the content of the response.
*
*
* @return read of response content
*
* @throws IOException
*/
public BufferedReader contentAsReader() throws IOException
{
ByteSource content = contentAsByteSource();
BufferedReader reader = null;
if (content != null)
{
reader = content.asCharSource(Charsets.UTF_8).openBufferedStream();
}
return reader;
}
/**
* Returns response content as stream.
*
*
* @return response content as stram
*
* @throws IOException
*/
public InputStream contentAsStream() throws IOException
{
ByteSource content = contentAsByteSource();
InputStream stream = null;
if (content != null)
{
stream = content.openBufferedStream();
}
return stream;
}
/**
* Returns the response content as string.
*
*
* @return response content
*
* @throws IOException
*/
public String contentAsString() throws IOException
{
ByteSource content = contentAsByteSource();
String value = null;
if (content != null)
{
value = content.asCharSource(Charsets.UTF_8).read();
}
return value;
}
/**
* Transforms the response content from json to the given type.
*
* @param <T> object type
* @param type object type
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the json content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentFromJson(Class<T> type) throws IOException
{
return contentTransformed(type, ContentType.JSON);
}
/**
* Transforms the response content from xml to the given type.
*
* @param <T> object type
* @param type object type
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the xml content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentFromXml(Class<T> type) throws IOException
{
return contentTransformed(type, ContentType.XML);
}
/**
* Transforms the response content to the given type. The method uses the
* content-type header to pick the right {@link ContentTransformer}.
*
* @param <T> object type
* @param type object type
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentTransformed(Class<T> type) throws IOException
{
String contentType = getFirstHeader("Content-Type");
if (Strings.isNullOrEmpty(contentType))
{
throw new ContentTransformerException(
"response does not return a Content-Type header");
}
return contentTransformed(type, contentType);
}
/**
* Transforms the response content from xml to the given type.
*
* @param <T> object type
* @param type object type
* @param contentType type to pick {@link ContentTransformer}
*
* @throws ContentTransformerNotFoundException if no
* {@link ContentTransformer} could be found for the content-type
*
* @return transformed object
*
* @throws IOException
*/
public <T> T contentTransformed(Class<T> type, String contentType)
throws IOException
{
T object = null;
ByteSource source = contentAsByteSource();
if (source != null)
{
ContentTransformer transformer = createTransformer(type, contentType);
object = transformer.unmarshall(type, contentAsByteSource());
}
return object;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the first header value for the given header name or {@code null}.
*
*
* @param name header name
*
* @return header value or {@code null}
*/
public String getFirstHeader(String name)
{
return Iterables.getFirst(getHeaders().get(name), null);
}
/**
* Returns {@code true} if the response was successful. A response is
* successful, if the status code is greater than 199 and lower than 400.
*
* @return {@code true} if the response was successful
*/
public boolean isSuccessful()
{
int status = getStatus();
return (status > 199) && (status < 400);
}
}

View File

@@ -0,0 +1,409 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import org.apache.shiro.codec.Base64;
import sonia.scm.util.HttpUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
/**
* Base class for http requests.
*
* @author Sebastian Sdorra
* @param <T> request implementation
*
* @since 1.46
*/
public abstract class BaseHttpRequest<T extends BaseHttpRequest>
{
/**
* Constructs a new {@link BaseHttpRequest}.
*
*
* @param client http client
* @param method http method
* @param url url
*/
public BaseHttpRequest(AdvancedHttpClient client, String method, String url)
{
this.client = client;
this.method = method;
this.url = url;
}
//~--- methods --------------------------------------------------------------
/**
* Executes the request and returns the http response.
*
*
* @return http response
*
* @throws IOException
*/
public AdvancedHttpResponse request() throws IOException
{
return client.request(this);
}
/**
* Implementing classes should return {@code this}.
*
*
* @return request instance
*/
protected abstract T self();
/**
* Enabled http basic authentication.
*
*
* @param username username for http basic authentication
* @param password password for http basic authentication
*
* @return http request instance
*/
public T basicAuth(String username, String password)
{
String auth = Strings.nullToEmpty(username).concat(":").concat(
Strings.nullToEmpty(password));
auth = Base64.encodeToString(auth.getBytes(Charsets.ISO_8859_1));
headers.put("Authorization", "Basic ".concat(auth));
return self();
}
/**
* Enable or disabled gzip decoding. The default value is false.
*
*
* @param decodeGZip true to enable gzip decoding
*
* @return request instance
*/
public T decodeGZip(boolean decodeGZip)
{
this.decodeGZip = decodeGZip;
return self();
}
/**
* Enable or disable certificate validation of ssl certificates. The default
* value is false.
*
*
* @param disableCertificateValidation true to disable certificate validation
*
* @return request instance
*/
public T disableCertificateValidation(boolean disableCertificateValidation)
{
this.disableCertificateValidation = disableCertificateValidation;
return self();
}
/**
* Enable or disable the validation of ssl hostnames. The default value is
* false.
*
*
* @param disableHostnameValidation true to disable ssl hostname validation
*
* @return request instance
*/
public T disableHostnameValidation(boolean disableHostnameValidation)
{
this.disableHostnameValidation = disableHostnameValidation;
return self();
}
/**
* Add http headers to request.
*
*
* @param name header name
* @param values header values
*
* @return request instance
*/
public T header(String name, Object... values)
{
for (Object v : values)
{
headers.put(name, toString(v));
}
return self();
}
/**
* Add http headers to request.
*
*
* @param name header name
* @param values header values
*
* @return request instance
*/
public T headers(String name, Iterable<? extends Object> values)
{
for (Object v : values)
{
headers.put(name, toString(v));
}
return self();
}
/**
* Ignore proxy settings. The default value is false.
*
*
* @param ignoreProxySettings true to ignore proxy settings.
*
* @return request instance
*/
public T ignoreProxySettings(boolean ignoreProxySettings)
{
this.ignoreProxySettings = ignoreProxySettings;
return self();
}
/**
* Appends a query parameter to the request.
*
*
* @param name name of query parameter
* @param values query parameter values
*
* @return request instance
*/
public T queryString(String name, Object... values)
{
for (Object v : values)
{
appendQueryString(name, v);
}
return self();
}
/**
* Appends a query parameter to the request.
*
*
* @param name name of query parameter
* @param values query parameter values
*
* @return request instance
*/
public T queryStrings(String name, Iterable<? extends Object> values)
{
for (Object v : values)
{
appendQueryString(name, v);
}
return self();
}
//~--- get methods ----------------------------------------------------------
/**
* Return a map with http headers used for the request.
*
*
* @return map with http headers
*/
public Multimap<String, String> getHeaders()
{
return headers;
}
/**
* Returns the http method for the request.
*
*
* @return http method of request
*/
public String getMethod()
{
return method;
}
/**
* Returns the url for the request.
*
*
* @return url of the request
*/
public String getUrl()
{
return url;
}
/**
* Returns true if the request decodes gzip compression.
*
*
* @return true if the request decodes gzip compression
*/
public boolean isDecodeGZip()
{
return decodeGZip;
}
/**
* Returns true if the verification of ssl certificates is disabled.
*
*
* @return true if certificate verification is disabled
*/
public boolean isDisableCertificateValidation()
{
return disableCertificateValidation;
}
/**
* Returns true if the ssl hostname validation is disabled.
*
*
* @return true if the ssl hostname validation is disabled
*/
public boolean isDisableHostnameValidation()
{
return disableHostnameValidation;
}
/**
* Returns true if the proxy settings are ignored.
*
*
* @return true if the proxy settings are ignored
*/
public boolean isIgnoreProxySettings()
{
return ignoreProxySettings;
}
//~--- methods --------------------------------------------------------------
/**
* Returns the value url encoded.
*
*
* @param value value to encode
*
* @return encoded value
*/
protected String encoded(Object value)
{
return HttpUtil.encode(Strings.nullToEmpty(toString(value)));
}
/**
* Returns string representation of the given object or {@code null}, if the
* object is {@code null}.
*
*
* @param object object
*
* @return string representation or {@code null}
*/
protected String toString(Object object)
{
return (object != null)
? object.toString()
: null;
}
private void appendQueryString(String name, Object value)
{
StringBuilder buffer = new StringBuilder();
if (url.contains("?"))
{
buffer.append("&");
}
else
{
buffer.append("?");
}
buffer.append(encoded(name)).append("=").append(encoded(value));
url = url.concat(buffer.toString());
}
//~--- fields ---------------------------------------------------------------
/** http client */
protected final AdvancedHttpClient client;
/** http header */
private final Multimap<String, String> headers = LinkedHashMultimap.create();
/** http method */
private final String method;
/** ignore proxy settings */
private boolean ignoreProxySettings = false;
/** disable ssl hostname validation */
private boolean disableHostnameValidation = false;
/** disable ssl certificate validation */
private boolean disableCertificateValidation = false;
/** decode gzip */
private boolean decodeGZip = false;
/** url of request */
private String url;
}

View File

@@ -0,0 +1,97 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteSource;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
/**
* {@link ByteSource} content for {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class ByteSourceContent implements Content
{
/**
* Constructs a new {@link ByteSourceContent}.
*
*
* @param byteSource byte source
*/
public ByteSourceContent(ByteSource byteSource)
{
this.byteSource = byteSource;
}
//~--- methods --------------------------------------------------------------
/**
* Sets the content length for the request.
*
*
* @param request http request
*
* @throws IOException
*/
@Override
public void prepare(AdvancedHttpRequestWithBody request) throws IOException
{
request.contentLength(byteSource.size());
}
/**
* Copies the content of the byte source to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
@Override
public void process(OutputStream output) throws IOException
{
byteSource.copyTo(output);
}
//~--- fields ---------------------------------------------------------------
/** byte source */
private final ByteSource byteSource;
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
/**
* Content of a {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public interface Content
{
/**
* Prepares the {@link AdvancedHttpRequestWithBody} for the request content.
* Implementations can set the content type, content length or custom headers
* for the request.
*
*
* @param request request
*
* @throws IOException
*/
public void prepare(AdvancedHttpRequestWithBody request) throws IOException;
/**
* Copies the content to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
public void process(OutputStream output) throws IOException;
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
import com.google.common.io.ByteSource;
import sonia.scm.plugin.ExtensionPoint;
/**
* Transforms {@link ByteSource} content to an object and vice versa. This class
* is an extension point, this means that plugins can define their own
* {@link ContentTransformer} implementations by implementing the interface and
* annotate the implementation with the {@link sonia.scm.plugin.ext.Extension}
* annotation.
*
* @author Sebastian Sdorra
* @since 1.46
*/
@ExtensionPoint
public interface ContentTransformer
{
/**
* Returns {@code true} if the transformer is responsible for the given
* object and content type.
*
* @param type object type
* @param contentType content type
*
* @return {@code true} if the transformer is responsible
*/
public boolean isResponsible(Class<?> type, String contentType);
/**
* Marshalls the given object into a {@link ByteSource}.
*
*
* @param object object to marshall
*
* @return string content
*/
public ByteSource marshall(Object object);
/**
* Unmarshall the {@link ByteSource} content to an object of the given type.
*
*
* @param type type of result object
* @param content content
* @param <T> type of result object
*
* @return
*/
public <T> T unmarshall(Class<T> type, ByteSource content);
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* A {@link ContentTransformerException} is thrown if an error occurs during
* content transformation by an {@link ContentTransformer}.
*
* @author Sebastian Sdorra
*
* @since 1.46
*/
public class ContentTransformerException extends RuntimeException
{
/** Field description */
private static final long serialVersionUID = 367333504151208563L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new {@link ContentTransformerException}.
*
*
* @param message exception message
*/
public ContentTransformerException(String message)
{
super(message);
}
/**
* Constructs a new {@link ContentTransformerException}.
*
*
* @param message exception message
* @param cause exception cause
*/
public ContentTransformerException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* The ContentTransformerNotFoundException is thrown, if no
* {@link ContentTransformer} could be found for the given type.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class ContentTransformerNotFoundException
extends ContentTransformerException
{
/** Field description */
private static final long serialVersionUID = 6374525163951460938L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new ContentTransformerNotFoundException.
*
*
* @param message exception message
*/
public ContentTransformerNotFoundException(String message)
{
super(message);
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* Content-Types.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public final class ContentType
{
/** json content type */
public static final String JSON = "application/json";
/** xml content type */
public static final String XML = "application/xml";
//~--- constructors ---------------------------------------------------------
private ContentType() {}
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Sets the content of the file to the request.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class FileContent implements Content
{
/**
* Constructs a new {@link FileContent}.
*
*
* @param file file
*/
public FileContent(File file)
{
this.file = file;
}
//~--- methods --------------------------------------------------------------
/**
* Sets the content length of the file as request header.
*
*
* @param request request
*/
@Override
public void prepare(AdvancedHttpRequestWithBody request)
{
request.contentLength(file.length());
}
/**
* Copies the content of the file to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
@Override
public void process(OutputStream output) throws IOException
{
InputStream stream = null;
try
{
stream = new FileInputStream(file);
ByteStreams.copy(stream, output);
}
finally
{
Closeables.close(stream, true);
}
}
//~--- fields ---------------------------------------------------------------
/** file */
private final File file;
}

View File

@@ -0,0 +1,139 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
import sonia.scm.util.HttpUtil;
/**
* The form builder is able to add form parameters to a request.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class FormContentBuilder
{
/**
* Constructs a new {@link FormContentBuilder}.
*
*
* @param request request
*/
public FormContentBuilder(AdvancedHttpRequestWithBody request)
{
this.request = request;
}
//~--- methods --------------------------------------------------------------
/**
* Build the formular content and append it to the request.
*
*
* @return request instance
*/
public AdvancedHttpRequestWithBody build()
{
request.contentType("application/x-www-form-urlencoded");
request.stringContent(builder.toString());
return request;
}
/**
* Adds a formular parameter.
*
*
* @param name parameter name
* @param values parameter values
*
* @return {@code this}
*/
public FormContentBuilder fields(String name, Iterable<? extends Object> values)
{
for (Object v : values)
{
append(name, v);
}
return this;
}
/**
* Adds a formular parameter.
*
*
* @param name parameter name
* @param values parameter values
*
* @return {@code this}
*/
public FormContentBuilder field(String name, Object... values)
{
for (Object v : values)
{
append(name, v);
}
return this;
}
private void append(String name, Object value)
{
if (!Strings.isNullOrEmpty(name))
{
if (builder.length() > 0)
{
builder.append("&");
}
builder.append(HttpUtil.encode(name)).append("=");
if (value != null)
{
builder.append(HttpUtil.encode(value.toString()));
}
}
}
//~--- fields ---------------------------------------------------------------
/** content builder */
private final StringBuilder builder = new StringBuilder();
/** request */
private final AdvancedHttpRequestWithBody request;
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
/**
* Http methods.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public final class HttpMethod
{
/** http delete method */
public static final String DELETE = "DELETE";
/** http get method */
public static final String GET = "GET";
/** http head method */
public static final String HEAD = "HEAD";
/** http options method */
public static final String OPTIONS = "OPTIONS";
/** http post method */
public static final String POST = "POST";
/** http put method */
public static final String PUT = "PUT";
//~--- constructors ---------------------------------------------------------
private HttpMethod() {}
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
/**
* Byte array content for {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class RawContent implements Content
{
/**
* Constructs a new {@link RawContent}.
*
*
* @param data data
*/
public RawContent(byte[] data)
{
this.data = data;
}
//~--- methods --------------------------------------------------------------
/**
* Sets the length of the byte array as http header.
*
*
* @param request request
*/
@Override
public void prepare(AdvancedHttpRequestWithBody request)
{
request.contentLength(data.length);
}
/**
* Writes the byte array to the output stream.
*
*
* @param output output stream
*
* @throws IOException
*/
@Override
public void process(OutputStream output) throws IOException
{
output.write(data);
}
//~--- get methods ----------------------------------------------------------
/**
* Returns content data.
*
*
* @return content data
*/
@VisibleForTesting
byte[] getData()
{
return data;
}
//~--- fields ---------------------------------------------------------------
/** byte array */
private final byte[] data;
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.net.ahc;
//~--- JDK imports ------------------------------------------------------------
import java.nio.charset.Charset;
/**
* String content for {@link AdvancedHttpRequestWithBody}.
*
* @author Sebastian Sdorra
* @since 1.46
*/
public class StringContent extends RawContent
{
/**
* Constructs a new {@link StringContent}.
*
*
* @param content content
* @param charset charset
*/
public StringContent(String content, Charset charset)
{
super(content.getBytes(charset));
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
/**
* Advanced http client.
*/
package sonia.scm.net.ahc;

View File

@@ -80,7 +80,7 @@ public abstract class AbstractRepositoryManager implements RepositoryManager
protected void fireEvent(HandlerEventType event, Repository repository,
Repository oldRepository)
{
ScmEventBus.getInstance().post(new RepositoryEvent(event, repository,
ScmEventBus.getInstance().post(new RepositoryModificationEvent(event, repository,
oldRepository));
}

View File

@@ -73,12 +73,28 @@ public final class Branch implements Serializable
*
*
* @param name name of the branch
*
* @deprecated use {@link Branch#Branch(String, String)} instead
*/
@Deprecated
public Branch(String name)
{
this.name = name;
}
/**
* Constructs a new branch.
*
*
* @param name name of the branch
* @param revision latest revision of the branch
*/
public Branch(String name, String revision)
{
this.name = name;
this.revision = revision;
}
//~--- methods --------------------------------------------------------------
/**
@@ -104,7 +120,8 @@ public final class Branch implements Serializable
final Branch other = (Branch) obj;
return Objects.equal(name, other.name);
return Objects.equal(name, other.name)
&& Objects.equal(revision, other.revision);
}
/**
@@ -116,7 +133,7 @@ public final class Branch implements Serializable
@Override
public int hashCode()
{
return Objects.hashCode(name);
return Objects.hashCode(name, revision);
}
/**
@@ -131,6 +148,7 @@ public final class Branch implements Serializable
//J-
return Objects.toStringHelper(this)
.add("name", name)
.add("revision", revision)
.toString();
//J+
}
@@ -148,8 +166,21 @@ public final class Branch implements Serializable
return name;
}
/**
* Returns the latest revision of the branch.
*
* @return latest revision of branch
*/
public String getRevision()
{
return revision;
}
//~--- fields ---------------------------------------------------------------
/** name of the branch */
private String name;
/** Field description */
private String revision;
}

View File

@@ -132,7 +132,9 @@ public class Changeset extends BasicPropertiesAware
final Changeset other = (Changeset) obj;
return Objects.equal(id, other.id) && Objects.equal(date, other.date)
//J-
return Objects.equal(id, other.id)
&& Objects.equal(date, other.date)
&& Objects.equal(author, other.author)
&& Objects.equal(description, other.description)
&& Objects.equal(parents, other.parents)
@@ -140,6 +142,7 @@ public class Changeset extends BasicPropertiesAware
&& Objects.equal(branches, other.branches)
&& Objects.equal(modifications, other.modifications)
&& Objects.equal(properties, other.properties);
//J+
}
/**
@@ -206,7 +209,9 @@ public class Changeset extends BasicPropertiesAware
}
/**
* Returns the branches of the changeset.
* Returns the branches of the changeset. In the most cases a changeset is
* only related to one branch, but in the case of receive hooks it is possible
* that a changeset is related to more than a branch.
*
*
* @return branches of the changeset

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
import sonia.scm.event.Event;
/**
* Event which causes clearing of repository cache.
*
* @author Sebastian Sdorra
* @since 1.50
*/
@Event
public class ClearRepositoryCacheEvent {
private final Repository repository;
/**
* Constructs a new instance.
*
* @param repository repository
*/
public ClearRepositoryCacheEvent(Repository repository) {
this.repository = repository;
}
/**
* Returns repository.
*
* @return repository
*/
public Repository getRepository() {
return repository;
}
}

View File

@@ -136,8 +136,9 @@ public class Permission implements PermissionObject, Serializable
final Permission other = (Permission) obj;
return Objects.equal(name, other.name) && Objects.equal(type, other.type)
&& Objects.equal(groupPermission, groupPermission);
return Objects.equal(name, other.name)
&& Objects.equal(type, other.type)
&& Objects.equal(groupPermission, other.groupPermission);
}
/**

View File

@@ -35,12 +35,10 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Objects;
import sonia.scm.HandlerEventType;
import sonia.scm.event.AbstractHandlerEvent;
import sonia.scm.event.Event;
import sonia.scm.event.HandlerEvent;
/**
* The RepositoryEvent is fired if a {@link Repository} object changes.
@@ -49,7 +47,7 @@ import sonia.scm.event.HandlerEvent;
* @since 1.23
*/
@Event
public final class RepositoryEvent extends AbstractHandlerEvent<Repository>
public class RepositoryEvent extends AbstractHandlerEvent<Repository>
{
/**

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
import sonia.scm.HandlerEventType;
import sonia.scm.ModificationHandlerEvent;
import sonia.scm.event.Event;
/**
* Event which is fired whenever a repository is modified.
*
* @author Sebastian Sdorra
* @since 1.48
*/
@Event
public final class RepositoryModificationEvent extends RepositoryEvent implements ModificationHandlerEvent<Repository>
{
private final Repository itemBeforeModification;
/**
* Constructs a new {@link RepositoryModificationEvent}.
*
* @param eventType event type
* @param item changed repository
* @param itemBeforeModification repository before it was modified
*/
public RepositoryModificationEvent(HandlerEventType eventType, Repository item, Repository itemBeforeModification)
{
super(eventType, item);
this.itemBeforeModification = itemBeforeModification;
}
@Override
public Repository getItemBeforeModification()
{
return itemBeforeModification;
}
}

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository.api;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
/**
* The HookBranchProvider returns informations about branch changes during the
* current hook.
*
* @author Sebastian Sdorra
* @since 1.45
*/
public interface HookBranchProvider
{
/**
* Returns the list of created or modified branch names.
*
* @return list of created or modified branches
*/
public List<String> getCreatedOrModified();
/**
* Returns the list deleted or closed branch names.
*
* @return list of deleted or closed branches
*/
public List<String> getDeletedOrClosed();
}

View File

@@ -43,8 +43,9 @@ import sonia.scm.repository.spi.HookContextProvider;
/**
* The context for all repository hooks. With the {@link HookContext} class it
* is able to send messages back to the client and retrieve {@link Changeset}s
* which are added during this push/commit.
* is able to send messages back to the client, retrieve {@link Changeset}s
* which are added during this push/commit and gives informations about changed
* branches and tags.
*
* @author Sebastian Sdorra
* @since 1.33
@@ -78,12 +79,59 @@ public final class HookContext
//~--- get methods ----------------------------------------------------------
/**
* Returns a {@link HookBranchProvider} which is able to return informations
* about changed branches during the current hook.
*
* @return {@link HookBranchProvider}
*
* @throws HookFeatureIsNotSupportedException if the feature is not supported
* by the underlying provider
*
* @since 1.45
*/
public HookBranchProvider getBranchProvider()
{
if (logger.isDebugEnabled())
{
logger.debug("create branch provider for repository {}",
repository.getName());
}
return provider.getBranchProvider();
}
/**
* Returns a {@link HookTagProvider} which is able to return informations
* about changed tags during the current hook.
*
* @return {@link HookTagProvider}
*
* @throws HookFeatureIsNotSupportedException if the feature is not supported
* by the underlying provider
*
* @since 1.50
*/
public HookTagProvider getTagProvider()
{
if (logger.isDebugEnabled())
{
logger.debug("create tag provider for repository {}",
repository.getName());
}
return provider.getTagProvider();
}
/**
* Returns a {@link HookChangesetBuilder} which is able to return all
* {@link Changeset}'s during this push/commit.
*
*
* @return {@link HookChangesetBuilder}
*
* @throws HookFeatureIsNotSupportedException if the feature is not supported
* by the underlying provider
*/
public HookChangesetBuilder getChangesetProvider()
{
@@ -111,6 +159,9 @@ public final class HookContext
*
* @return {@link HookMessageProvider} which is able to send message back to
* the scm client
*
* @throws HookFeatureIsNotSupportedException if the feature is not supported
* by the underlying provider
*/
public HookMessageProvider getMessageProvider()
{
@@ -138,12 +189,12 @@ public final class HookContext
//~--- fields ---------------------------------------------------------------
/** Field description */
private PreProcessorUtil preProcessorUtil;
/** pre processor util */
private final PreProcessorUtil preProcessorUtil;
/** Field description */
private HookContextProvider provider;
/** hook context provider */
private final HookContextProvider provider;
/** Field description */
private Repository repository;
/** repository */
private final Repository repository;
}

View File

@@ -37,4 +37,30 @@ package sonia.scm.repository.api;
* @author Sebastian Sdorra
* @since 1.33
*/
public enum HookFeature { MESSAGE_PROVIDER, CHANGESET_PROVIDER; }
public enum HookFeature
{
/**
* Hook message provider
*/
MESSAGE_PROVIDER,
/**
* Hook changeset provider
*/
CHANGESET_PROVIDER,
/**
* Hook branch provider
*
* @since 1.45
*/
BRANCH_PROVIDER,
/**
* Hook tag provider
*
* @since 1.50
*/
TAG_PROVIDER;
}

View File

@@ -0,0 +1,59 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository.api;
import java.util.List;
import sonia.scm.repository.Tag;
/**
* The HookTagProvider returns informations about tags during the
* current hook.
*
* @since 1.50
* @author Sebastian Sdorra
*/
public interface HookTagProvider {
/**
* Return all tags which are delivered during the current hook.
*
* @return all tags of current hook
*/
public List<Tag> getCreatedTags();
/**
* Return all tags which are deleted during the current hook.
*
* @return all deleted tags of current hook
*/
public List<Tag> getDeletedTags();
}

View File

@@ -40,6 +40,7 @@ import com.github.legman.Subscribe;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -50,11 +51,6 @@ import sonia.scm.HandlerEventType;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.event.ScmEventBus;
import sonia.scm.repository.BlameResult;
import sonia.scm.repository.Branches;
import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
import sonia.scm.repository.PreProcessorUtil;
import sonia.scm.repository.Repository;
@@ -63,7 +59,6 @@ import sonia.scm.repository.RepositoryEvent;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryPermissions;
import sonia.scm.repository.Tags;
import sonia.scm.repository.spi.RepositoryServiceProvider;
import sonia.scm.repository.spi.RepositoryServiceResolver;
import sonia.scm.security.ScmSecurityException;
@@ -71,6 +66,8 @@ import sonia.scm.security.ScmSecurityException;
//~--- JDK imports ------------------------------------------------------------
import java.util.Set;
import sonia.scm.event.ScmEventBus;
import sonia.scm.repository.ClearRepositoryCacheEvent;
/**
* The {@link RepositoryServiceFactory} is the entrypoint of the repository api.
@@ -285,38 +282,44 @@ public final class RepositoryServiceFactory
//~--- inner classes --------------------------------------------------------
/**
* TODO find a more elegant way
*
*
* @version Enter version here..., 12/06/16
* @author Enter your name here...
* Hook and listener to clear all relevant repository caches.
*/
private static class CacheClearHook
{
private final Set<Cache<?, ?>> caches = Sets.newHashSet();
/**
* Constructs ...
* Constructs a new instance and collect all repository relevant
* caches from the {@link CacheManager}.
*
*
* @param cacheManager
* @param cacheManager cache manager
*/
public CacheClearHook(CacheManager cacheManager)
{
this.blameCache = cacheManager.getCache(BlameCommandBuilder.CACHE_NAME);
this.browseCache = cacheManager.getCache(BrowseCommandBuilder.CACHE_NAME);
this.logCache = cacheManager.getCache(LogCommandBuilder.CACHE_NAME);
this.tagsCache = cacheManager.getCache(TagsCommandBuilder.CACHE_NAME);
this.branchesCache =
cacheManager.getCache(BranchesCommandBuilder.CACHE_NAME);
this.caches.add(cacheManager.getCache(BlameCommandBuilder.CACHE_NAME));
this.caches.add(cacheManager.getCache(BrowseCommandBuilder.CACHE_NAME));
this.caches.add(cacheManager.getCache(LogCommandBuilder.CACHE_NAME));
this.caches.add(cacheManager.getCache(TagsCommandBuilder.CACHE_NAME));
this.caches.add(cacheManager.getCache(BranchesCommandBuilder.CACHE_NAME));
}
//~--- methods ------------------------------------------------------------
/**
* Method description
* Clear caches on explicit repository cache clear event.
*
* @param event clear event
*/
@Subscribe
public void onEvent(ClearRepositoryCacheEvent event) {
clearCaches(event.getRepository().getId());
}
/**
* Clear caches on repository push.
*
*
* @param event
* @param event hook event
*/
@Subscribe(referenceType = ReferenceType.STRONG)
public void onEvent(PostReceiveRepositoryHookEvent event)
@@ -332,11 +335,10 @@ public final class RepositoryServiceFactory
}
/**
* Method description
* Clear caches on repository delete event.
*
*
* @param repository
* @param event
* @param repository changed repository
* @param event repository event
*/
@Subscribe(referenceType = ReferenceType.STRONG)
public void onEvent(RepositoryEvent event)
@@ -346,13 +348,7 @@ public final class RepositoryServiceFactory
clearCaches(event.getItem().getId());
}
}
/**
* Method description
*
*
* @param repositoryId
*/
@SuppressWarnings("unchecked")
private void clearCaches(final String repositoryId)
{
@@ -361,32 +357,11 @@ public final class RepositoryServiceFactory
logger.debug("clear caches for repository id {}", repositoryId);
}
RepositoryCacheKeyPredicate filter =
new RepositoryCacheKeyPredicate(repositoryId);
blameCache.removeAll(filter);
browseCache.removeAll(filter);
logCache.removeAll(filter);
tagsCache.removeAll(filter);
branchesCache.removeAll(filter);
RepositoryCacheKeyPredicate predicate = new RepositoryCacheKeyPredicate(repositoryId);
caches.forEach((cache) -> {
cache.removeAll(predicate);
});
}
//~--- fields -------------------------------------------------------------
/** blame cache */
private final Cache<BlameCommandBuilder.CacheKey, BlameResult> blameCache;
/** branches cache */
private final Cache<BranchesCommandBuilder.CacheKey, Branches> branchesCache;
/** browse cache */
private final Cache<BrowseCommandBuilder.CacheKey, BrowserResult> browseCache;
/** log cache */
private final Cache<LogCommandBuilder.CacheKey, ChangesetPagingResult> logCache;
/** tags cache */
private final Cache<TagsCommandBuilder.CacheKey, Tags> tagsCache;
}

View File

@@ -33,16 +33,20 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.repository.api.HookBranchProvider;
import sonia.scm.repository.api.HookException;
import sonia.scm.repository.api.HookFeature;
import sonia.scm.repository.api.HookFeatureIsNotSupportedException;
import sonia.scm.repository.api.HookMessageProvider;
import sonia.scm.repository.api.HookContext;
import sonia.scm.repository.api.HookTagProvider;
//~--- JDK imports ------------------------------------------------------------
import java.util.Set;
/**
* Repository type specific provider for {@link HookContext}.
*
* @author Sebastian Sdorra
* @since 1.33
@@ -51,10 +55,10 @@ public abstract class HookContextProvider
{
/**
* Method description
*
*
* @return
* Return the provider specific {@link HookMessageProvider} or throws a {@link HookFeatureIsNotSupportedException}.
* The method will throw a {@link HookException} if the client is already disconnected.
*
* @return provider specific {@link HookMessageProvider}
*/
public final HookMessageProvider getMessageProvider()
{
@@ -70,7 +74,7 @@ public abstract class HookContextProvider
//~--- methods --------------------------------------------------------------
/**
* Method description
* Mark client connection as disconnected.
*
*/
final void handleClientDisconnect()
@@ -81,32 +85,52 @@ public abstract class HookContextProvider
//~--- get methods ----------------------------------------------------------
/**
* Method description
* Returns a set of supported hook features of the client.
*
*
* @return
* @return supported features
*/
public abstract Set<HookFeature> getSupportedFeatures();
/**
* Method description
*
*
* @return
* Return the provider specific {@link HookBranchProvider} or throws a {@link HookFeatureIsNotSupportedException}.
*
* @return provider specific {@link HookBranchProvider}
*
* @since 1.45
*/
public HookBranchProvider getBranchProvider()
{
throw new HookFeatureIsNotSupportedException(HookFeature.BRANCH_PROVIDER);
}
/**
* Return the provider specific {@link HookTagProvider} or throws a {@link HookFeatureIsNotSupportedException}.
*
* @return provider specific {@link HookTagProvider}
*
* @since 1.50
*/
public HookTagProvider getTagProvider()
{
throw new HookFeatureIsNotSupportedException(HookFeature.TAG_PROVIDER);
}
/**
* Return the provider specific {@link HookChangesetProvider} or throws a {@link HookFeatureIsNotSupportedException}.
*
* @return provider specific {@link HookChangesetProvider}
*/
public HookChangesetProvider getChangesetProvider()
{
throw new HookFeatureIsNotSupportedException(
HookFeature.CHANGESET_PROVIDER);
throw new HookFeatureIsNotSupportedException(HookFeature.CHANGESET_PROVIDER);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @return
* Creates a new provider specific {@link HookMessageProvider} or throws a {@link HookFeatureIsNotSupportedException}.
*
* @return provider specific {@link HookChangesetProvider}
*/
protected HookMessageProvider createMessageProvider()
{
@@ -115,6 +139,5 @@ public abstract class HookContextProvider
//~--- fields ---------------------------------------------------------------
/** Field description */
private boolean clientDisconnected = false;
}

View File

@@ -0,0 +1,65 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.schedule;
import java.io.Closeable;
/**
* Scheduler is able to run tasks on the future in a background thread. Task can be scheduled with cron like expression.
* <strong>Note:</strong> Task are always executed in an administrative context.
* @author Sebastian Sdorra
* @since 1.47
*/
public interface Scheduler extends Closeable {
/**
* Schedule a new task for future execution.
*
* @param expression cron expression
* @param runnable action
*
* @return cancelable task
*/
public Task schedule(String expression, Runnable runnable);
/**
* Schedule a new task for future execution. The method will create a new instance of the runnable for every
* execution. The runnable can use injection.
*
* @param expression cron expression
* @param runnable action class
*
* @return cancelable task
*/
public Task schedule(String expression, Class<? extends Runnable> runnable);
}

View File

@@ -0,0 +1,47 @@
/***
* Copyright (c) 2015, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* https://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.schedule;
/**
* Tasks are executed in the future and can be running more than once. A task execution can be canceled.
*
* @author Sebastian Sdorra
* @since 1.47
*/
public interface Task {
/**
* Cancel task execution.
*/
public void cancel();
}

View File

@@ -35,7 +35,8 @@ package sonia.scm.security;
/**
*
* Encrypts and decrypts string values.
*
* @author Sebastian Sdorra
* @since 1.7
*/
@@ -43,22 +44,20 @@ public interface CipherHandler
{
/**
* Method description
* Decrypts the given value.
*
* @param value encrypted value
*
* @param value
*
* @return
* @return decrypted value
*/
public String decode(String value);
/**
* Method description
* Encrypts the given value.
*
* @param value plain text value to encrypt.
*
* @param value
*
* @return
* @return encrypted value
*/
public String encode(String value);
}

View File

@@ -53,7 +53,7 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -66,32 +66,32 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
* Default implementation of the {@link CipherHandler}, which uses AES for
* encryption and decryption.
*
* @author Sebastian Sdorra
* @since 1.7
*/
public class DefaultCipherHandler implements CipherHandler
{
public class DefaultCipherHandler implements CipherHandler {
/** Field description */
/** used cipher type */
public static final String CIPHER_TYPE = "AES/CTR/PKCS5PADDING";
/** Field description */
/** digest type for key generation */
public static final String DIGEST_TYPE = "SHA-512";
/** Field description */
/** string encoding */
public static final String ENCODING = "UTF-8";
/** Field description */
/** default key length */
public static final int KEY_LENGTH = 16;
/** Field description */
/** default salt length */
public static final int SALT_LENGTH = 16;
/** Field description */
private static final String CIPHERKEY_FILENAME = ".cipherkey";
@VisibleForTesting
static final String CIPHERKEY_FILENAME = ".cipherkey";
/** Field description */
private static final char[] KEY_BASE = new char[]
{
'1', '4', '7', '3', 'F', '2', '1', 'E', '-', 'C', '4', 'C', '4', '-', '4',
@@ -99,96 +99,72 @@ public class DefaultCipherHandler implements CipherHandler
'E', 'C', '7', '7', '2', 'E'
};
/** Field description */
private static final String KEY_TYPE = "AES";
/** the logger for DefaultCipherHandler */
private static final Logger logger =
LoggerFactory.getLogger(DefaultCipherHandler.class);
//~--- constructors ---------------------------------------------------------
private static final Logger logger = LoggerFactory.getLogger(DefaultCipherHandler.class);
private final SecureRandom random = new SecureRandom();
private final char[] key;
/**
* Constructs a new DefaultCipherHandler. Note this constructor is only for
* unit tests.
*
*
* @param key
* @param key default encryption key
*
* @since 1.38
*/
@VisibleForTesting
protected DefaultCipherHandler(String key)
{
protected DefaultCipherHandler(String key) {
this.key = key.toCharArray();
}
/**
* Constructs ...
*
*
* @param context
* @param keyGenerator
*
* Constructs a new instance and reads the default key from the scm home directory,
* if the key file does not exists it will be generated with the {@link KeyGenerator}.
*
* @param context SCM-Manager context provider
* @param keyGenerator key generator for default key generation
*/
public DefaultCipherHandler(SCMContextProvider context,
KeyGenerator keyGenerator)
{
public DefaultCipherHandler(SCMContextProvider context, KeyGenerator keyGenerator) {
File configDirectory = new File(context.getBaseDirectory(), "config");
IOUtil.mkdirs(configDirectory);
cipherKeyFile = new File(configDirectory, CIPHERKEY_FILENAME);
File cipherKeyFile = new File(configDirectory, CIPHERKEY_FILENAME);
try
{
if (cipherKeyFile.exists())
{
loadKey();
}
else
{
try {
if (cipherKeyFile.exists()) {
key = loadKey(cipherKeyFile);
} else {
key = keyGenerator.createKey().toCharArray();
storeKey();
storeKey(cipherKeyFile);
}
}
catch (IOException ex)
{
} catch (IOException ex) {
throw new CipherException("could not create CipherHandler", ex);
}
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param value
*
* @return
*/
@Override
public String decode(String value)
{
public String decode(String value) {
return decode(key, value);
}
/**
* Method description
* Decodes the given value with the provided key.
*
* @param plainKey key which is used for decoding
* @param value encrypted value
*
* @param plainKey
* @param value
*
* @return
* @return decrypted value
*/
public String decode(char[] plainKey, String value)
{
public String decode(char[] plainKey, String value) {
String result = null;
try
{
try {
byte[] encodedInput = Base64.decode(value);
byte[] salt = new byte[SALT_LENGTH];
byte[] encoded = new byte[encodedInput.length - SALT_LENGTH];
@@ -206,52 +182,35 @@ public class DefaultCipherHandler implements CipherHandler
byte[] decoded = cipher.doFinal(encoded);
result = new String(decoded, ENCODING);
}
catch (Exception ex)
{
logger.error("could not decode string", ex);
throw new CipherException(ex);
} catch (IOException | GeneralSecurityException ex) {
throw new CipherException("could not decode string", ex);
}
return result;
}
/**
* Method description
*
*
* @param value
*
* @return
*/
@Override
public String encode(String value)
{
public String encode(String value) {
return encode(key, value);
}
/**
* Method description
* Encrypts the given value with the provided key.
*
* @param plainKey key which is used for encoding
* @param value plain text value to encrypt
*
* @param plainKey
* @param value
*
* @return
* @return encrypted value
*/
public String encode(char[] plainKey, String value)
{
public String encode(char[] plainKey, String value) {
String res = null;
try
{
try {
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
IvParameterSpec iv = new IvParameterSpec(salt);
SecretKey secretKey = buildSecretKey(key);
SecretKey secretKey = buildSecretKey(plainKey);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_TYPE);
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKey, iv);
@@ -264,31 +223,14 @@ public class DefaultCipherHandler implements CipherHandler
System.arraycopy(encodedInput, 0, result, SALT_LENGTH,
result.length - SALT_LENGTH);
res = new String(Base64.encode(result), ENCODING);
}
catch (Exception ex)
{
logger.error("could not encode string", ex);
throw new CipherException(ex);
} catch (IOException | GeneralSecurityException ex) {
throw new CipherException("could not encode string", ex);
}
return res;
}
/**
* Method description
*
*
* @param plainKey
*
* @return
*
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
private SecretKey buildSecretKey(char[] plainKey)
throws UnsupportedEncodingException, NoSuchAlgorithmException
{
private SecretKey buildSecretKey(char[] plainKey) throws IOException, NoSuchAlgorithmException {
byte[] raw = new String(plainKey).getBytes(ENCODING);
MessageDigest digest = MessageDigest.getInstance(DIGEST_TYPE);
@@ -298,60 +240,18 @@ public class DefaultCipherHandler implements CipherHandler
return new SecretKeySpec(raw, KEY_TYPE);
}
/**
* Method description
*
*
* @throws IOException
*/
private void loadKey() throws IOException
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(new FileReader(cipherKeyFile));
private char[] loadKey(File cipherKeyFile) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(cipherKeyFile))) {
String line = reader.readLine();
key = decode(KEY_BASE, line).toCharArray();
}
finally
{
IOUtil.close(reader);
return decode(KEY_BASE, line).toCharArray();
}
}
/**
* Method description
*
*
* @throws FileNotFoundException
*/
private void storeKey() throws FileNotFoundException
{
private void storeKey(File cipherKeyFile) throws FileNotFoundException {
String storeKey = encode(KEY_BASE, new String(key));
PrintWriter output = null;
try
{
output = new PrintWriter(cipherKeyFile);
try (PrintWriter output = new PrintWriter(cipherKeyFile)) {
output.write(storeKey);
}
finally
{
IOUtil.close(output);
}
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private File cipherKeyFile;
/** Field description */
private char[] key = null;
/** Field description */
private SecureRandom random = new SecureRandom();
}

View File

@@ -56,17 +56,28 @@ public abstract class AbstractUserManager implements UserManager
*/
protected void fireEvent(HandlerEventType event, User user, User oldUser)
{
ScmEventBus.getInstance().post(new UserEvent(event, user, oldUser));
fireEvent(new UserModificationEvent(event, user, oldUser));
}
/**
* Send a {@link UserEvent} to the {@link ScmEventBus}.
* Creates a new {@link UserEvent} and calls {@link #fireEvent(sonia.scm.user.UserEvent)}.
*
* @param user user that has changed
* @param event type of change event
*/
protected void fireEvent(HandlerEventType event, User user)
{
ScmEventBus.getInstance().post(new UserEvent(event, user));
fireEvent(new UserEvent(event, user));
}
/**
* Send a {@link UserEvent} to the {@link ScmEventBus}.
*
* @param event user event
* @since 1.48
*/
protected void fireEvent(UserEvent event)
{
ScmEventBus.getInstance().post(event);
}
}

View File

@@ -46,7 +46,7 @@ import sonia.scm.event.Event;
* @since 1.23
*/
@Event
public final class UserEvent extends AbstractHandlerEvent<User>
public class UserEvent extends AbstractHandlerEvent<User>
{
/**

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2014, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.user;
import sonia.scm.HandlerEventType;
import sonia.scm.ModificationHandlerEvent;
import sonia.scm.event.Event;
/**
* Event which is fired whenever a user is modified.
*
* @author Sebastian Sdorra
* @since 1.48
*/
@Event
public class UserModificationEvent extends UserEvent implements ModificationHandlerEvent<User>
{
private final User itemBeforeModification;
/**
* Constructs a new {@link UserModificationEvent}.
*
* @param eventType type of event
* @param item changed user
* @param itemBeforeModification changed user before it was modified
*/
public UserModificationEvent(HandlerEventType eventType, User item, User itemBeforeModification)
{
super(eventType, item);
this.itemBeforeModification = itemBeforeModification;
}
@Override
public User getItemBeforeModification()
{
return itemBeforeModification;
}
}

View File

@@ -35,7 +35,9 @@ package sonia.scm.util;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import org.slf4j.Logger;
@@ -96,6 +98,12 @@ public final class HttpUtil
* @since 2.0.0
*/
public static final String HEADER_AUTHORIZATION = "Authorization";
/**
* content-length header
* @since 1.46
*/
public static final String HEADER_CONTENT_LENGTH = "Content-Length";
/**
* location header
@@ -115,6 +123,24 @@ public final class HttpUtil
/** authentication header */
public static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
/**
* The original host requested by the client in the Host HTTP request header.
* @since 1.47
*/
public static final String HEADER_X_FORWARDED_HOST = "X-Forwarded-Host";
/**
* The original port requested by the client.
* @since 1.47
*/
public static final String HEADER_X_FORWARDED_PORT = "X-Forwarded-Port";
/**
* The original protocol (http or https) requested by the client.
* @since 1.47
*/
public static final String HEADER_X_FORWARDED_PROTO = "X-Forwarded-Proto";
/**
* Default http port
* @since 1.5
@@ -315,8 +341,26 @@ public final class HttpUtil
}
/**
* Url decode.
* Creates the value for the content-disposition attachment header. The method
* creates the filename as specified in rfc6266.
*
* @param name attachment name
* @see <a href="http://tools.ietf.org/html/rfc6266#section-5">rfc6266 section 5</a>
* @return value of content-disposition header
* @since 1.46
*/
public static String createContentDispositionAttachmentHeader(String name)
{
StringBuilder buffer = new StringBuilder("attachment; ");
buffer.append("filename=\"").append(name).append("\"; ");
buffer.append("filename*=utf-8''").append(encode(name));
return buffer.toString();
}
/**
* Url decode.
*
* @param value value to decode
*
@@ -578,21 +622,31 @@ public final class HttpUtil
//~--- get methods ----------------------------------------------------------
/**
* Returns an absolute url with context path.
* Returns an absolute url with context path. The method creates the url from
* forwarding request headers, if they are available.
*
*
* @param request http client request
* @param pathSegments
*
* @return absolute url with context path
*
* @see <a href="https://goo.gl/PvGQyH">Issue 748</a>
* @since 1.16
*/
public static String getCompleteUrl(HttpServletRequest request,
String... pathSegments)
{
String baseUrl =
request.getRequestURL().toString().replace(request.getRequestURI(),
Util.EMPTY_STRING).concat(request.getContextPath());
String baseUrl;
if (isForwarded(request))
{
baseUrl = createForwardedBaseUrl(request);
}
else
{
baseUrl = createBaseUrl(request);
}
if (Util.isNotEmpty(pathSegments))
{
@@ -622,6 +676,24 @@ public final class HttpUtil
return append(configuration.getBaseUrl(), path);
}
/**
* Method description
*
*
* @param request
* @param header
* @param defaultValue
*
* @return
*/
public static String getHeader(HttpServletRequest request, String header,
String defaultValue)
{
String value = request.getHeader(header);
return Objects.firstNonNull(value, defaultValue);
}
/**
* Returns the port of the url parameter.
*
@@ -776,6 +848,21 @@ public final class HttpUtil
return "chunked".equals(request.getHeader("Transfer-Encoding"));
}
/**
* Returns {@code true} if the request is forwarded by a reverse proxy. The
* method uses the X-Forwarded-Host header to identify a forwarded request.
*
* @param request servlet request
*
* @return {@code true} if the request is forwarded
*
* @since 1.47
*/
public static boolean isForwarded(HttpServletRequest request)
{
return !Strings.isNullOrEmpty(request.getHeader(HEADER_X_FORWARDED_HOST));
}
/**
* Returns true if the http request is send by the scm-manager web interface.
*
@@ -790,4 +877,74 @@ public final class HttpUtil
return SCM_CLIENT_WUI.equalsIgnoreCase(
request.getHeader(HEADER_SCM_CLIENT));
}
//~--- methods --------------------------------------------------------------
/**
* Creates base url for request url.
*
* @param request http servlet request
*
* @return base url from request
*
* @since 1.47
*/
@VisibleForTesting
static String createBaseUrl(HttpServletRequest request)
{
return request.getRequestURL().toString().replace(request.getRequestURI(),
Util.EMPTY_STRING).concat(request.getContextPath());
}
/**
* Creates base url from forwarding request headers.
*
* @param request http servlet request
*
* @return base url from forward headers
*
* @since 1.47
*/
@VisibleForTesting
static String createForwardedBaseUrl(HttpServletRequest request)
{
String proto = getHeader(request, HEADER_X_FORWARDED_PROTO,
request.getScheme());
String host;
String fhost = getHeader(request, HEADER_X_FORWARDED_HOST,
request.getScheme());
String port = request.getHeader(HEADER_X_FORWARDED_PORT);
int s = fhost.indexOf(SEPARATOR_PORT);
if (s > 0)
{
host = fhost.substring(0, s);
if (Strings.isNullOrEmpty(port))
{
port = fhost.substring(s + 1);
}
}
else
{
host = fhost;
}
StringBuilder buffer = new StringBuilder(proto);
buffer.append(SEPARATOR_SCHEME).append(host).append(SEPARATOR_PORT);
if (Strings.isNullOrEmpty(port))
{
buffer.append(String.valueOf(request.getServerPort()));
}
else
{
buffer.append(port);
}
buffer.append(request.getContextPath());
return buffer.toString();
}
}

View File

@@ -35,6 +35,7 @@ package sonia.scm.util;
//~--- JDK imports ------------------------------------------------------------
import com.google.common.net.UrlEscapers;
import java.net.MalformedURLException;
import java.net.URL;
@@ -138,8 +139,11 @@ public class UrlBuilder
{
if (Util.isNotEmpty(name) && Util.isNotEmpty(value))
{
url = new StringBuilder(url).append(separator).append(name).append(
HttpUtil.SEPARATOR_PARAMETER_VALUE).append(value).toString();
url = new StringBuilder(url)
.append(separator).append(name)
.append(HttpUtil.SEPARATOR_PARAMETER_VALUE)
.append(UrlEscapers.urlFragmentEscaper().escape(value))
.toString();
separator = HttpUtil.SEPARATOR_PARAMETER;
parameterAdded = true;
}

View File

@@ -0,0 +1,257 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Charsets;
import com.google.common.base.Objects;
import static com.google.common.base.Preconditions.*;
//~--- JDK imports ------------------------------------------------------------
import java.nio.charset.Charset;
/**
* The software agent that is acting on behalf of a user. The user agent
* represents a browser or one of the repository client (svn, git or hg).
*
* @author Sebastian Sdorra <s.sdorra@gmail.com>
* @since 1.45
*/
public final class UserAgent
{
/**
* Constructs a new user agent
*
*
* @param name
* @param browser
* @param basicAuthenticationCharset
*/
private UserAgent(String name, boolean browser,
Charset basicAuthenticationCharset)
{
this.name = checkNotNull(name);
this.browser = browser;
this.basicAuthenticationCharset = checkNotNull(basicAuthenticationCharset);
}
//~--- methods --------------------------------------------------------------
/**
* Returns the {@link Builder} for the UserAgent.
*
*
* @param name name of the UserAgent
*
* @return builder for UserAgent
*/
public static Builder builder(String name)
{
return new Builder(name);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final UserAgent other = (UserAgent) obj;
return Objects.equal(name, other.name)
&& Objects.equal(browser, other.browser)
&& Objects.equal(basicAuthenticationCharset, basicAuthenticationCharset);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
return Objects.hashCode(name, browser, basicAuthenticationCharset);
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
//J-
return Objects.toStringHelper(this)
.add("name", name)
.add("browser", browser)
.add("basicAuthenticationCharset", basicAuthenticationCharset)
.toString();
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the {@link Charset}, which is used to decode the basic
* authentication header.
*
* @return {@link Charset} for basic authentication
*/
public Charset getBasicAuthenticationCharset()
{
return basicAuthenticationCharset;
}
/**
* Returns the name of UserAgent.
*
*
* @return name of UserAgent
*/
public String getName()
{
return name;
}
/**
* Returns {@code true} if UserAgent is a browser.
*
*
* @return {@code true} if UserAgent is a browser
*/
public boolean isBrowser()
{
return browser;
}
//~--- inner classes --------------------------------------------------------
/**
* Builder class for {@link UserAgent}.
*/
public static class Builder
{
/**
* Constructs a new UserAgent builder.
*
*
* @param name name of the UserAgent
*/
public Builder(String name)
{
this.name = name;
}
//~--- methods ------------------------------------------------------------
/**
* Sets {@link Charset} which is used to decode the basic authentication.
*
*
* @param basicAuthenticationCharset charset for basic authentication
*
* @return {@code this}
*/
public Builder basicAuthenticationCharset(
Charset basicAuthenticationCharset)
{
this.basicAuthenticationCharset =
checkNotNull(basicAuthenticationCharset);
return this;
}
/**
* Set to {@code true} if the {@link UserAgent} is a browser.
*
*
* @param browser {@code true} for a browser
*
* @return {@code this}
*/
public Builder browser(boolean browser)
{
this.browser = browser;
return this;
}
/**
* Builds the {@link UserAgent}.
*
*
* @return new {@link UserAgent}
*/
public UserAgent build()
{
return new UserAgent(name, browser, basicAuthenticationCharset);
}
//~--- fields -------------------------------------------------------------
/** name of UserAgent */
private final String name;
/** indicator for browsers */
private boolean browser = true;
/** basic authentication charset */
private Charset basicAuthenticationCharset = Charsets.ISO_8859_1;
}
//~--- fields ---------------------------------------------------------------
/** basic authentication charset */
private final Charset basicAuthenticationCharset;
/** indicator for browsers */
private final boolean browser;
/** name of UserAgent */
private final String name;
}

View File

@@ -0,0 +1,157 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.util.HttpUtil;
//~--- JDK imports ------------------------------------------------------------
import java.util.Locale;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
/**
* Parser for User-Agent header. The UserAgentParser parses the User-Agent
* header and returns a {@link UserAgent} object.
*
* @author Sebastian Sdorra <s.sdorra@gmail.com>
* @since 1.45
*/
@Singleton
public final class UserAgentParser
{
/** name of the cache */
@VisibleForTesting
static final String CACHE_NAME = "sonia.scm.user-agent";
/** unknown UserAgent */
@VisibleForTesting
static final UserAgent UNKNOWN = UserAgent.builder("UNKNOWN").build();
/** logger */
private static final Logger logger =
LoggerFactory.getLogger(UserAgentParser.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new UserAgentParser.
*
*
* @param providers set of providers
* @param cacheManager cache manager
*/
@Inject
public UserAgentParser(Set<UserAgentProvider> providers,
CacheManager cacheManager)
{
this.providers = providers;
this.cache = cacheManager.getCache(CACHE_NAME);
}
//~--- methods --------------------------------------------------------------
/**
* Extracts the User-Agent header and returns an {@link UserAgent} object.
*
*
* @param request http request
*
* @return {@link UserAgent} object
*/
public UserAgent parse(HttpServletRequest request)
{
return parse(request.getHeader(HttpUtil.HEADER_USERAGENT));
}
/**
* Parses the User-Agent header and returns a {@link UserAgent} object.
*
*
* @param userAgent User-Agent header
*
* @return {@link UserAgent} object
*/
public UserAgent parse(String userAgent)
{
String uas = Strings.nullToEmpty(userAgent).toLowerCase(Locale.ENGLISH);
UserAgent ua = cache.get(uas);
if (ua == null)
{
for (UserAgentProvider provider : providers)
{
ua = provider.parseUserAgent(uas);
if (ua != null)
{
break;
}
}
if (ua == null)
{
ua = UNKNOWN;
}
cache.put(uas, ua);
}
logger.trace("return user-agent {} for {}", ua, userAgent);
return ua;
}
//~--- fields ---------------------------------------------------------------
/** cache for parsed UserAgents */
private final Cache<String, UserAgent> cache;
/** set of providers */
private final Set<UserAgentProvider> providers;
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
import sonia.scm.plugin.ExtensionPoint;
/**
* Provider to parse User-Agent header and returns an {@link UserAgent} object.
* The {@link UserAgentProvider} is used by the {@link UserAgentParser}.
*
* @author Sebastian Sdorra <s.sdorra@gmail.com>
* @since 1.45
*/
@ExtensionPoint(multi = true)
public interface UserAgentProvider
{
/**
* Parses the User-Agent header and returns a {@link UserAgent} object.
*
*
* @param userAgentString User-Agent header
*
* @return {@link UserAgent} object
*/
public UserAgent parseUserAgent(String userAgentString);
}

View File

@@ -93,9 +93,7 @@ public class AuthenticationFilter extends HttpFilter
* @param tokenGenerators web token generators
*/
@Inject
public AuthenticationFilter(ScmConfiguration configuration,
Set<WebTokenGenerator> tokenGenerators)
{
public AuthenticationFilter(ScmConfiguration configuration, Set<WebTokenGenerator> tokenGenerators) {
this.configuration = configuration;
this.tokenGenerators = tokenGenerators;
}
@@ -106,7 +104,6 @@ public class AuthenticationFilter extends HttpFilter
* Handles authentication, if a one of the {@link WebTokenGenerator} returns
* an {@link AuthenticationToken}.
*
*
* @param request servlet request
* @param response servlet response
* @param chain filter chain
@@ -222,7 +219,6 @@ public class AuthenticationFilter extends HttpFilter
private AuthenticationToken createToken(HttpServletRequest request)
{
AuthenticationToken token = null;
for (WebTokenGenerator generator : tokenGenerators)
{
token = generator.createToken(request);

View File

@@ -144,33 +144,24 @@ public abstract class PermissionFilter extends HttpFilter
if (hasPermission(repository, writeRequest))
{
if (logger.isTraceEnabled())
{
logger.trace("{} access to repository {} for user {} granted",
getActionAsString(writeRequest), repository.getName(),
getUserName(subject));
}
logger.trace("{} access to repository {} for user {} granted",
getActionAsString(writeRequest), repository.getName(),
getUserName(subject));
chain.doFilter(request, response);
}
else
{
if (logger.isInfoEnabled())
{
logger.info("{} access to repository {} for user {} denied",
getActionAsString(writeRequest), repository.getName(),
getUserName(subject));
}
logger.info("{} access to repository {} for user {} denied",
getActionAsString(writeRequest), repository.getName(),
getUserName(subject));
sendAccessDenied(request, response, subject);
}
}
else
{
if (logger.isDebugEnabled())
{
logger.debug("repository not found");
}
logger.debug("repository not found");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
@@ -193,12 +184,7 @@ public abstract class PermissionFilter extends HttpFilter
}
catch (ScmSecurityException | AuthorizationException ex)
{
if (logger.isWarnEnabled())
{
logger.warn("user {} has not enough permissions",
subject.getPrincipal());
}
logger.warn("user " + subject.getPrincipal() + " has not enough permissions", ex);
sendAccessDenied(request, response, subject);
}

View File

@@ -45,7 +45,7 @@ import javax.servlet.http.HttpServletRequestWrapper;
public class SecurityHttpServletRequestWrapper extends HttpServletRequestWrapper
{
/**
/**
* Constructs ...
*
*
@@ -61,9 +61,6 @@ public class SecurityHttpServletRequestWrapper extends HttpServletRequestWrapper
//~--- get methods ----------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public String getRemoteUser()
{