Initial integration of the new repository api into Archiva 1.2

git-svn-id: https://svn.apache.org/repos/asf/archiva/branches/archiva-with-new-repoapi@743242 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
James William Dumay 2009-02-11 06:11:40 +00:00
parent 1114cc8a55
commit 3adfa0de12
34 changed files with 2157 additions and 10 deletions

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-base</artifactId>
<version>1.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>archiva-repository-api</artifactId>
<version>1.2-SNAPSHOT</version>
<name>Apache Base :: Repository API</name>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.3</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,162 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
/**
* MimeType sniffing for repository Artifacts
*/
public class MimeTypes
{
private static final Logger log = Logger.getLogger(MimeTypes.class);
private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
private String resource = "/mime.types";
private Map mimeMap = new HashMap();
public MimeTypes()
{
load(resource);
}
/**
* Get the Mime Type for the provided filename.
*
* @param filename the filename to obtain the mime type for.
* @return a mime type String, or null if filename is null, has no extension, or no mime type is associated with it.
*/
public String getMimeType( String filename )
{
String value = null;
if ( !StringUtils.isEmpty( filename ) )
{
int index = filename.lastIndexOf( '.' );
if ( index >= 0 )
{
value = (String) mimeMap.get( filename.substring( index + 1 ).toLowerCase() );
}
}
if (value == null)
{
value = DEFAULT_MIME_TYPE;
}
return value;
}
private void load( String resourceName )
{
ClassLoader cloader = this.getClass().getClassLoader();
/* Load up the mime types table */
URL mimeURL = cloader.getResource( resourceName );
if ( mimeURL == null )
{
throw new IllegalStateException( "Unable to find resource " + resourceName );
}
InputStream mimeStream = null;
try
{
mimeStream = mimeURL.openStream();
load( mimeStream );
}
catch ( IOException e )
{
log.error( "Unable to load mime map " + resourceName + " : " + e.getMessage(), e );
}
finally
{
IOUtils.closeQuietly( mimeStream );
}
}
private void load( InputStream mimeStream )
{
mimeMap.clear();
InputStreamReader reader = null;
BufferedReader buf = null;
try
{
reader = new InputStreamReader( mimeStream );
buf = new BufferedReader( reader );
String line = null;
while ( ( line = buf.readLine() ) != null )
{
line = line.trim();
if ( line.length() == 0 )
{
// empty line. skip it
continue;
}
if ( line.startsWith( "#" ) )
{
// Comment. skip it
continue;
}
StringTokenizer tokenizer = new StringTokenizer( line );
if ( tokenizer.countTokens() > 1 )
{
String type = tokenizer.nextToken();
while ( tokenizer.hasMoreTokens() )
{
String extension = tokenizer.nextToken().toLowerCase();
this.mimeMap.put( extension, type );
}
}
}
}
catch ( IOException e )
{
log.error( "Unable to read mime types from input stream : " + e.getMessage(), e );
}
finally
{
IOUtils.closeQuietly( buf );
IOUtils.closeQuietly( reader );
}
}
}

View File

@ -0,0 +1,58 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.Arrays;
import org.apache.commons.lang.StringUtils;
public final class PathUtils
{
public static String getRepositoryId(String uri)
{
if (uri == null)
return null;
final String[] parts = StringUtils.split(uri, '/');
if (parts != null && parts.length >= 1)
{
return parts[0];
}
return null;
}
public static String getLogicalPath(String uri)
{
String result = "/";
if (uri == null)
return result;
final String[] parts = StringUtils.split(uri, '/');
if (parts.length > 0)
{
result = "/" + StringUtils.join(Arrays.asList(parts).subList(1, parts.length), "/");
}
if (StringUtils.isEmpty(result))
{
result = "/";
}
return result;
}
}

View File

@ -0,0 +1,46 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
/**
* Represents a Maven repository
*/
public interface Repository
{
/**
* Name of the repository
* @return name
*/
String getName();
/**
* Id of the repository
* @return id
*/
String getId();
/**
* Local file path of the repository
* @return path
*/
File getLocalPath();
}

View File

@ -0,0 +1,78 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.InputStream;
import java.io.OutputStream;
/**
* RepositoryContext abstracts away the HTTP request/response
* for use retreiving or storing data in a repository
*/
public interface RepositoryContext extends ResourceContext
{
/**
* Gets the ID for a Repostory
* @return repositoryId
*/
String getRepositoryId();
/**
* Gets the logical path of the request
* @return logicalPath
*/
String getLogicalPath();
/**
* Gets the principal for the current context
* @return
*/
String getPrincipal();
/**
* Gets the type of Request the RepositoryContext Represents
* @return
*/
RequestType getRequestType();
/**
* Gets the InputStream for the request body
* @return inputStream
*/
InputStream getInputStream();
/**
* Gets the OutputStream for the request response
* @return outputStream
*/
OutputStream getOutputStream();
/**
* Gets the ContentLength of the Response
* @return contentLength
*/
int getContentLength();
/**
* Gets the ContentType of the Response
* @return
*/
String getContentType();
}

View File

@ -0,0 +1,35 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.Map;
/**
* RepositoryFactory produces repositories for the RepositoryManager
* @author jdumay
*/
public interface RepositoryFactory
{
/**
* Returns a map of Repository objects keyed by the repository id
* @return repositoryMap
*/
Map<String, Repository> getRepositories();
}

View File

@ -0,0 +1,82 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
/**
* RepositoryManager
*/
public interface RepositoryManager
{
/**
* Checks if the RepositoryManager instance can handle the data represented by the ResourceContext
*
* If the RepositoryManager can handle the ResourceContext it should return
* the same ResourceContext or a mutated version which is then passed to other methods on object.
*
* Should return null if unable to handle the ResourceContext
*
* @param context
* @return context
*/
ResourceContext handles(ResourceContext context);
/**
* Returns a list of Status objects that represent the current status
* of the resources and collections represented by the ResourceContext
*
* If the ResourceContext is a collection then stat should return
* a list of Status objects for all children where the first element in
* the list is the status of the collection itself
*
* If the ResourceContext is a resource (file) then the returned list should
* only return a list with a single Status representing the ResourceContext
*
* @param context
* @return statusList
*/
List<Status> stat(ResourceContext context);
/**
* Reads the data represented by the ResourceContext to the OutputStream
* @param context
* @param os
* @return success
*/
boolean read(ResourceContext context, OutputStream os);
/**
* Writes the data represented by the ResourceContext from the InputStream
* @param context
* @param is
* @return success
*/
boolean write(ResourceContext context, InputStream is);
/**
* Checks if the repositoryId exists as part of this repository manager
* @param repositoryId
* @return exists
*/
boolean exists(String repositoryId);
}

View File

@ -0,0 +1,31 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* RepositoryManagerException
*/
public class RepositoryManagerException extends RuntimeException
{
public RepositoryManagerException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -0,0 +1,35 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.Collection;
/**
* Factory for RepositoryManagers
* @author jdumay
*/
public interface RepositoryManagerFactory
{
/**
* Returns a collection of all available RepositoryManagers
* @return repositoryManagers
*/
Collection<RepositoryManager> getRepositoryManagers();
}

View File

@ -0,0 +1,39 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to weight RepositoryManagers found in the container.
*
* Lower values appear are served first while higher values are served last
*
* @author jdumay
*/
@Target(ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface RepositoryManagerWeight
{
int value();
}

View File

@ -0,0 +1,55 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.RepositoryManager;
import org.apache.archiva.repository.api.RepositoryManagerWeight;
import java.util.Comparator;
public class RepositoryWeightComparitor implements Comparator<RepositoryManager>
{
public int compare(RepositoryManager repo1, RepositoryManager repo2)
{
RepositoryManagerWeight repo1Weight = getRepositoryManagerWeight(repo1);
RepositoryManagerWeight repo2Weight = getRepositoryManagerWeight(repo2);
if (repo1Weight == null)
{
return -1;
}
if (repo2Weight == null)
{
return 1;
}
if (repo1Weight.value() > repo2Weight.value())
{
return 1;
}
if (repo1Weight.value() < repo2Weight.value())
{
return -1;
}
return 0;
}
private RepositoryManagerWeight getRepositoryManagerWeight(RepositoryManager manager)
{
return manager.getClass().getAnnotation(RepositoryManagerWeight.class);
}
}

View File

@ -0,0 +1,26 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
public enum RequestType
{
Read,
Write
}

View File

@ -0,0 +1,38 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Represents the Resource to be manipulated by the RepositoryManager
*/
public interface ResourceContext
{
/**
* Get the Logical Path of the resource
* @return
*/
String getLogicalPath();
/**
* Get the repository ID of the resource
* @return
*/
String getRepositoryId();
}

View File

@ -0,0 +1,26 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
public enum ResourceType
{
Collection,
Resource
}

View File

@ -0,0 +1,192 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.util.Comparator;
/**
* Represents the Status of an resource from a RepositoryManager
*/
public final class Status
{
private static final MimeTypes mimeTypes = new MimeTypes();
private Status()
{
}
private ResourceType resourceType;
private String contentType;
private long contentLength;
private long lastModified;
private long createdDate;
private String name;
/**
* Sets the Name of the resource
* @param name
*/
public void setName(String name)
{
this.name = name;
}
/**
* Sets the Name of the resource
* @return name
*/
public String getName()
{
return name;
}
/**
* Gets the length of the resources
* @return length
*/
public long getContentLength()
{
return contentLength;
}
/**
* Sets the length of the resource
* @param contentLength
*/
public void setContentLength(long contentLength)
{
this.contentLength = contentLength;
}
/**
* Gets the Content Type of the resource
* @return
*/
public String getContentType()
{
return contentType;
}
/**
* Sets the contentType of the resource
* @param contentType
*/
public void setContentType(String contentType)
{
this.contentType = contentType;
}
/**
* Gets the created date of a resource
* @return createdDate
*/
public long getCreatedDate()
{
return createdDate;
}
/**
* Sets the created date of a resource
* @param createdDate
*/
public void setCreatedDate(long createdDate)
{
this.createdDate = createdDate;
}
/**
* Gets the last modified date of a resource
* @return lastModified
*/
public long getLastModified()
{
return lastModified;
}
/**
* Sets the last modified date of a resource
* @param lastModified
*/
public void setLastModified(long lastModified)
{
this.lastModified = lastModified;
}
/**
* Gets the resource type
* @return resourceType
*/
public ResourceType getResourceType()
{
return resourceType;
}
/**
* Sets the resource type
* @param resourceType
*/
public void setResourceType(ResourceType resourceType)
{
this.resourceType = resourceType;
}
/**
* Builds a Status object for the given file.
*
* @param file
* @return status
*/
public static Status fromFile(File file)
{
Status status = new Status();
status.setName(file.getName());
status.setLastModified(file.lastModified());
status.setCreatedDate(file.lastModified());
if (file.isDirectory())
{
status.setResourceType(ResourceType.Collection);
}
else
{
status.setContentType(mimeTypes.getMimeType(file.getName()));
status.setContentLength(file.length());
status.setResourceType(ResourceType.Resource);
}
return status;
}
/**
* Comparator for Status names
*/
public static class StatusNameComparator implements Comparator<Status>
{
public int compare(Status status1, Status status2)
{
return status1.getName().compareTo(status2.getName());
}
}
}

View File

@ -0,0 +1,28 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Marker interface for the default implementation of the RepositoryManager
* which can be used in other parts of the system without having to go via the servlet.
*/
public interface SystemRepositoryManager extends RepositoryManager
{
}

View File

@ -0,0 +1,28 @@
package org.apache.archiva.repository.api.interceptor;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Interceptor which runs after the RepositoryManager
* @author jdumay
*/
public interface PostRepositoryInterceptor extends RepositoryInterceptor
{
}

View File

@ -0,0 +1,27 @@
package org.apache.archiva.repository.api.interceptor;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Interceptor which runs before the RepositoryManager
*/
public interface PreRepositoryInterceptor extends RepositoryInterceptor
{
}

View File

@ -0,0 +1,35 @@
package org.apache.archiva.repository.api.interceptor;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.RepositoryContext;
/**
* Repository Interceptors get executed before and after
* the RepositoryManager for every request.
*/
public interface RepositoryInterceptor
{
/**
* Intercepts the RepositoryContext for the current request
* @param context
*/
void intercept(RepositoryContext context);
}

View File

@ -0,0 +1,37 @@
package org.apache.archiva.repository.api.interceptor;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.Collection;
/**
* Factory for RepositoryIntercetpors
*
* @author jdumay
* @param <I>
*/
public interface RepositoryInterceptorFactory<I extends RepositoryInterceptor>
{
/**
* Returns all the available RepositoryInterceptors
* @return repositoryInterceptors
*/
Collection<I> getRepositoryInterceptors();
}

View File

@ -0,0 +1,127 @@
# This file controls what Internet media types are sent to the client for
# given file extension(s). Sending the correct media type to the client
# is important so they know how to handle the content of the file.
# Extra types can either be added here or by using an AddType directive
# in your config files. For more information about Internet media types,
# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
# registry is at <http://www.iana.org/assignments/media-types/>.
# MIME type Extensions
application/andrew-inset ez
application/atom+xml atom
application/java-archive jar
application/mac-binhex40 hqx
application/mac-compactpro cpt
application/mathml+xml mathml
application/msword doc
application/octet-stream bin dms lha lzh exe class so dll dmg
application/oda oda
application/ogg ogg
application/pdf pdf
application/pgp-encrypted pgp
application/postscript ai eps ps
application/rdf+xml rdf
application/smil smi smil
application/srgs gram
application/srgs+xml grxml
application/vnd.mif mif
application/vnd.mozilla.xul+xml xul
application/vnd.ms-excel xls
application/vnd.ms-powerpoint ppt
application/vnd.rn-realmedia rm
application/vnd.wap.wbxml wbxml
application/vnd.wap.wmlc wmlc
application/vnd.wap.wmlscriptc wmlsc
application/voicexml+xml vxml
application/x-bcpio bcpio
application/x-cdlink vcd
application/x-chess-pgn pgn
application/x-cpio cpio
application/x-csh csh
application/x-director dcr dir dxr
application/x-dvi dvi
application/x-futuresplash spl
application/x-gtar gtar
application/x-hdf hdf
application/x-java-jnlp-file jnlp
application/x-javascript js
application/x-koan skp skd skt skm
application/x-latex latex
application/x-netcdf nc cdf
application/x-sh sh
application/x-shar shar
application/x-shockwave-flash swf
application/x-stuffit sit
application/x-sv4cpio sv4cpio
application/x-sv4crc sv4crc
application/x-tar tar
application/x-tcl tcl
application/x-tex tex
application/x-texinfo texinfo texi
application/x-troff t tr roff
application/x-troff-man man
application/x-troff-me me
application/x-troff-ms ms
application/x-ustar ustar
application/x-wais-source src
application/xhtml+xml xhtml xht
application/xml xml xsl pom
application/xml-dtd dtd
application/xslt+xml xslt
application/zip zip
audio/basic au snd
audio/midi mid midi kar
audio/mpeg mpga mp2 mp3
audio/x-aiff aif aiff aifc
audio/x-mpegurl m3u
audio/x-pn-realaudio ram ra
audio/x-wav wav
chemical/x-pdb pdb
chemical/x-xyz xyz
image/bmp bmp
image/cgm cgm
image/gif gif
image/ief ief
image/jp2 jp2
image/jpeg jpeg jpg jpe
image/pict pict pic pct
image/png png
image/svg+xml svg
image/tiff tiff tif
image/vnd.djvu djvu djv
image/vnd.wap.wbmp wbmp
image/x-cmu-raster ras
image/x-icon ico
image/x-macpaint pntg pnt mac
image/x-portable-anymap pnm
image/x-portable-bitmap pbm
image/x-portable-graymap pgm
image/x-portable-pixmap ppm
image/x-quicktime qtif qti
image/x-rgb rgb
image/x-xbitmap xbm
image/x-xpixmap xpm
image/x-xwindowdump xwd
model/iges igs iges
model/mesh msh mesh silo
model/vrml wrl vrml
text/calendar ics ifb
text/css css
text/html html htm
text/plain asc txt sha1 md5
text/richtext rtx
text/rtf rtf
text/sgml sgml sgm
text/tab-separated-values tsv
text/vnd.wap.wml wml
text/vnd.wap.wmlscript wmls
text/x-setext etx
video/mp4 mp4
video/mpeg mpeg mpg mpe
video/quicktime qt mov
video/vnd.mpegurl mxu m4u
video/x-dv dv dif
video/x-msvideo avi
video/x-sgi-movie movie
x-conference/x-cooltalk ice

View File

@ -0,0 +1,68 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.PathUtils;
import org.junit.Test;
import static org.junit.Assert.*;
public class PathUtilsTest
{
@Test
public void testRepositoryId() throws Exception
{
String path = "/myrepo/foo/bar";
assertEquals("myrepo", PathUtils.getRepositoryId(path));
path = "myrepo/foo/bar";
assertEquals("myrepo", PathUtils.getRepositoryId(path));
path = "/myrepo";
assertEquals("myrepo", PathUtils.getRepositoryId(path));
path = "mypath";
assertEquals("mypath", PathUtils.getRepositoryId(path));
path = "";
assertNull(PathUtils.getRepositoryId(path));
path = null;
assertNull("", PathUtils.getRepositoryId(path));
}
@Test
public void testLogicalPath() throws Exception
{
String path = "/helloworld/foo/bar/baz/";
assertEquals("/foo/bar/baz", PathUtils.getLogicalPath(path));
path = "/helloworld/foo/bar/baz";
assertEquals("/foo/bar/baz", PathUtils.getLogicalPath(path));
path = "helloworld/foo/bar/baz";
assertEquals("/foo/bar/baz", PathUtils.getLogicalPath(path));
path = "";
assertEquals("/", PathUtils.getLogicalPath(path));
path = null;
assertEquals("/", PathUtils.getLogicalPath(path));
}
}

View File

@ -0,0 +1,104 @@
package org.apache.archiva.repository.api;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
public class RepositoryWeightComparitorTest extends TestCase
{
public void testRepositoryManagerWeights() throws Exception
{
RepoManager2 manager2 = new RepoManager2();
RepoManager1 manager1 = new RepoManager1();
List<RepositoryManager> managers = new ArrayList<RepositoryManager>();
managers.add(manager2);
managers.add(manager1);
Collections.sort(managers, new RepositoryWeightComparitor());
assertEquals(manager1, managers.get(0));
assertEquals(manager2, managers.get(1));
}
@RepositoryManagerWeight(2)
class RepoManager2 implements RepositoryManager
{
public ResourceContext handles(ResourceContext context)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean exists(String repositoryId)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean read(ResourceContext context, OutputStream os)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public List<Status> stat(ResourceContext context)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean write(ResourceContext context, InputStream is)
{
throw new UnsupportedOperationException("Not supported yet.");
}
}
@RepositoryManagerWeight(1)
class RepoManager1 implements RepositoryManager
{
public ResourceContext handles(ResourceContext context)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean exists(String repositoryId)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean read(ResourceContext context, OutputStream os)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public List<Status> stat(ResourceContext context)
{
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean write(ResourceContext context, InputStream is)
{
throw new UnsupportedOperationException("Not supported yet.");
}
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<project>
<parent>
<artifactId>archiva-base</artifactId>
<groupId>org.apache.archiva</groupId>
<version>1.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository</artifactId>
<name>Archiva Base :: Repository</name>
<dependencies>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,54 @@
package org.apache.archiva.repository;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.Repository;
import java.io.File;
public class DefaultRepository implements Repository
{
private final String id;
private final String name;
private final File localPath;
public DefaultRepository(String id, String name, File localPath)
{
this.id = id;
this.name = name;
this.localPath = localPath;
}
public String getId()
{
return id;
}
public File getLocalPath()
{
return localPath;
}
public String getName()
{
return name;
}
}

View File

@ -0,0 +1,144 @@
package org.apache.archiva.repository;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.Repository;
import org.apache.archiva.repository.api.RepositoryFactory;
import org.apache.archiva.repository.api.RepositoryManagerException;
import org.apache.archiva.repository.api.ResourceContext;
import org.apache.archiva.repository.api.Status;
import org.apache.archiva.repository.api.SystemRepositoryManager;
import org.apache.archiva.repository.api.RepositoryManagerWeight;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@RepositoryManagerWeight(9000)
public class DefaultRepositoryManager implements SystemRepositoryManager
{
private final RepositoryFactory repositoryFactory;
public DefaultRepositoryManager(RepositoryFactory repositoryFactory)
{
this.repositoryFactory = repositoryFactory;
}
public ResourceContext handles(ResourceContext context)
{
return context;
}
public boolean exists(String repositoryId)
{
return repositoryFactory.getRepositories().containsKey(repositoryId);
}
public boolean read(ResourceContext context, OutputStream os)
{
final Repository repository = repositoryFactory.getRepositories().get(context.getRepositoryId());
if (repository == null)
{
return false;
}
FileInputStream fis = null;
try
{
fis = new FileInputStream(new File(repository.getLocalPath(), context.getLogicalPath()));
IOUtils.copyLarge(fis, os);
return true;
}
catch (IOException e)
{
throw new RepositoryManagerException("Could not read resource from " + context.getLogicalPath(), e);
}
finally
{
IOUtils.closeQuietly(fis);
}
}
public boolean write(ResourceContext context, InputStream is)
{
final Repository repository = repositoryFactory.getRepositories().get(context.getRepositoryId());
if (repository == null)
{
return false;
}
final File newResource = new File(repository.getLocalPath(), context.getLogicalPath());
newResource.getParentFile().mkdirs();
FileOutputStream fos = null;
try
{
newResource.createNewFile();
fos = new FileOutputStream(newResource);
IOUtils.copy(is, fos);
return true;
}
catch (IOException e)
{
FileUtils.deleteQuietly(newResource);
throw new RepositoryManagerException("Could not write resource to " + context.getLogicalPath(), e);
}
finally
{
IOUtils.closeQuietly(fos);
}
}
public List<Status> stat(ResourceContext context)
{
final Repository repository = repositoryFactory.getRepositories().get(context.getRepositoryId());
if (repository != null)
{
final File file = new File(repository.getLocalPath(), context.getLogicalPath());
if (file.exists())
{
final ArrayList<Status> result = new ArrayList<Status>();
if (file.isDirectory())
{
result.add(Status.fromFile(file));
for (final File child : file.listFiles())
{
result.add(Status.fromFile(child));
}
}
if (file.isFile())
{
result.add(Status.fromFile(file));
}
return result;
}
return Collections.EMPTY_LIST;
}
return null;
}
}

View File

@ -13,9 +13,7 @@
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.archiva</groupId>
@ -42,5 +40,7 @@
<module>archiva-transaction</module>
<module>archiva-artifact-converter</module>
<module>archiva-converter</module>
<module>archiva-repository-api</module>
<module>archiva-repository</module>
</modules>
</project>
</project>

View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<project>
<parent>
<artifactId>archiva-web</artifactId>
<groupId>org.apache.archiva</groupId>
<version>1.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository-servlet</artifactId>
<name>Archiva Web :: Repository Servlet</name>
<dependencies>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,161 @@
package org.apache.archiva.web.servlet;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.PathUtils;
import org.apache.archiva.repository.api.MimeTypes;
import org.apache.archiva.repository.api.RepositoryContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.archiva.repository.api.RequestType;
import org.apache.commons.codec.binary.Base64;
public class HttpRepositoryContext implements RepositoryContext
{
private static final MimeTypes mimeTypes = new MimeTypes();
private HttpServletRequest request;
private HttpServletResponse response;
private final String logicalPath;
private final String principal;
private final String repositoryId;
private final RequestType requestType;
private int contentLength;
public HttpRepositoryContext(HttpServletRequest request, HttpServletResponse response)
{
this.request = request;
this.response = response;
this.repositoryId = PathUtils.getRepositoryId(request.getPathInfo());
this.logicalPath = PathUtils.getLogicalPath(request.getPathInfo());
if (request.getAuthType() != null && !HttpServletRequest.BASIC_AUTH.equals(request.getAuthType()))
{
throw new RuntimeException("Authentication type " + request.getAuthType() + " is not supported");
}
this.principal = getPrincipal(request);
if ("PUT".equals(request.getMethod()))
{
this.requestType = RequestType.Write;
}
else
{
this.requestType = RequestType.Read;
}
}
private static String getPrincipal(HttpServletRequest request)
{
String header = request.getHeader( "Authorization" );
// in tomcat this is : authorization=Basic YWRtaW46TWFuYWdlMDc=
if ( header == null )
{
header = request.getHeader( "authorization" );
}
if ( ( header != null ) && header.startsWith( "Basic " ) )
{
String base64Token = header.substring( 6 );
String token = new String( Base64.decodeBase64( base64Token.getBytes() ) );
String username = "";
int delim = token.indexOf( ':' );
if ( delim != ( -1 ) )
{
username = token.substring( 0, delim );
}
return username;
}
return null;
}
public String getLogicalPath()
{
return logicalPath;
}
public String getPrincipal()
{
return principal;
}
public String getRepositoryId()
{
return repositoryId;
}
public RequestType getRequestType()
{
return requestType;
}
public InputStream getInputStream()
{
try
{
return request.getInputStream();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public OutputStream getOutputStream()
{
try
{
//Head should not return a body
if ("HEAD".equals(request.getMethod()))
{
return null;
}
return response.getOutputStream();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public int getContentLength()
{
return contentLength;
}
public void setContentLength(int contentLength)
{
this.contentLength = contentLength;
}
public String getContentType()
{
return mimeTypes.getMimeType(logicalPath);
}
}

View File

@ -0,0 +1,117 @@
package org.apache.archiva.web.servlet;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.ResourceContext;
import org.apache.archiva.repository.api.Status;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.io.PrintWriter;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.apache.archiva.repository.api.ResourceType;
import org.apache.commons.io.output.ByteArrayOutputStream;
public final class IndexWriter
{
public static void write(List<Status> resources, ResourceContext context, HttpServletResponse resp, boolean writeContent) throws IOException
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintWriter writer = new PrintWriter(outputStream, true);
resp.setDateHeader("last-modified", new Date().getTime());
resp.setContentType("text/html");
writeDocumentStart(context, writer);
writeHyperlinks(resources, context, writer);
writeDocumentEnd(writer);
resp.setContentLength(outputStream.toByteArray().length);
if (writeContent)
{
resp.getOutputStream().write(outputStream.toByteArray());
}
}
private static void writeDocumentStart(ResourceContext context, PrintWriter writer)
{
writer.println("<html>");
writer.println("<head>");
writer.println("<title>Collection: " + context.getLogicalPath() + "</title>");
writer.println("</head>");
writer.println("<body>");
writer.println("<h3>Collection: " + context.getLogicalPath() + "</h3>");
//Check if not root
if (!"/".equals(context.getLogicalPath()))
{
File file = new File(context.getLogicalPath());
String parentName = file.getParent().equals("") ? "/" : file.getParent();
//convert to unix path in case archiva is hosted on windows
parentName = StringUtils.replace(parentName, "\\", "/" );
writer.println("<ul>");
writer.println("<li><a href=\"../\">" + parentName + "</a> <i><small>(Parent)</small></i></li>");
writer.println("</ul>");
}
writer.println("<ul>");
}
private static void writeDocumentEnd(PrintWriter writer)
{
writer.println("</ul>");
writer.println("</body>");
writer.println("</html>");
}
private static void writeHyperlinks(List<Status> resources, ResourceContext context, PrintWriter writer)
{
ArrayList<Status> sortedResources = new ArrayList<Status>(resources);
sortedResources.remove(0); //First entry is the stat for the collection itself
Collections.sort(sortedResources, new Status.StatusNameComparator());
for( Status status : sortedResources)
{
//Ignore hidden directories
if (!status.getName().startsWith("."))
{
writeHyperlink(writer, status);
}
}
}
private static void writeHyperlink(PrintWriter writer, Status status )
{
if (ResourceType.Collection.equals(status.getResourceType()))
{
writer.println("<li><a href=\"" + status.getName() + "/\">" + status.getName() + "</a></li>");
}
else
{
writer.println("<li><a href=\"" + status.getName() + "\">" + status.getName() + "</a></li>");
}
}
}

View File

@ -0,0 +1,190 @@
package org.apache.archiva.web.servlet;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.api.RepositoryContext;
import org.apache.archiva.repository.api.RepositoryManager;
import org.apache.archiva.repository.api.RepositoryManagerFactory;
import org.apache.archiva.repository.api.ResourceContext;
import org.apache.archiva.repository.api.Status;
import org.apache.archiva.repository.api.interceptor.PostRepositoryInterceptor;
import org.apache.archiva.repository.api.interceptor.PreRepositoryInterceptor;
import org.apache.archiva.repository.api.interceptor.RepositoryInterceptorFactory;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.archiva.repository.api.ResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RepositoryServlet extends HttpServlet
{
private static final Logger log = LoggerFactory.getLogger(RepositoryServlet.class);
private final RepositoryInterceptorFactory<PreRepositoryInterceptor> preRepositoryInterceptorFactory;
private final RepositoryInterceptorFactory<PostRepositoryInterceptor> postRepositoryInterceptorFactory;
private final RepositoryManagerFactory repositoryManagerFactory;
private static final String MKCOL_METHOD = "MKCOL";
private static final String LAST_MODIFIED = "last-modified";
public RepositoryServlet( RepositoryInterceptorFactory<PreRepositoryInterceptor> preRepositoryInterceptorFactory,
RepositoryInterceptorFactory<PostRepositoryInterceptor> postRepositoryInterceptorFactory,
RepositoryManagerFactory repositoryManagerFactory)
{
this.preRepositoryInterceptorFactory = preRepositoryInterceptorFactory;
this.postRepositoryInterceptorFactory = postRepositoryInterceptorFactory;
this.repositoryManagerFactory = repositoryManagerFactory;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setHeader("Server", "Apache Archiva");
resp.setDateHeader("Date", new Date().getTime());
//Backwards compatability with the weddav wagon
if (MKCOL_METHOD.equals(req.getMethod()))
{
resp.setStatus(HttpServletResponse.SC_CREATED);
return;
}
super.service(req, resp);
}
@Override
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
handleRequest(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
handleRequest(req, resp);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
handleRequest(req, resp);
}
private void handleRequest(final HttpServletRequest req, final HttpServletResponse resp)
throws IOException
{
log.debug("Request started");
HttpRepositoryContext context = new HttpRepositoryContext(req, resp);
log.debug("Running PreRepositoryInterceptors");
executePreRepositoryInterceptors(context);
log.debug("Executing Repository Manager");
runRepositoryManager(context, req, resp);
log.debug("Running PostRepositoryInterceptors");
executePostRepositoryInterceptors(context);
log.debug("Request Completed");
}
private void executePreRepositoryInterceptors(RepositoryContext context)
{
for (final PreRepositoryInterceptor interceptor : preRepositoryInterceptorFactory.getRepositoryInterceptors())
{
interceptor.intercept(context);
}
}
private void executePostRepositoryInterceptors(RepositoryContext context)
{
for (final PostRepositoryInterceptor interceptor : postRepositoryInterceptorFactory.getRepositoryInterceptors())
{
interceptor.intercept(context);
}
}
private void runRepositoryManager(final RepositoryContext context, final HttpServletRequest req, final HttpServletResponse resp)
throws IOException
{
for (final RepositoryManager manager : repositoryManagerFactory.getRepositoryManagers())
{
final ResourceContext resourceContext = manager.handles(context);
if (resourceContext != null)
{
log.debug("Request handled by " + manager.toString());
doContent(manager, resourceContext, req, resp);
break;
}
}
}
private void doContent(final RepositoryManager repositoryManager, final ResourceContext context, final HttpServletRequest req, final HttpServletResponse resp)
throws IOException
{
if ("PUT".equals(req.getMethod()))
{
repositoryManager.write(context, req.getInputStream());
return;
}
final List<Status> results = repositoryManager.stat(context);
if (!results.isEmpty())
{
final boolean withBody = !"HEAD".equals(req.getMethod());
final Status status = results.get(0);
if (ResourceType.Collection.equals(status.getResourceType()))
{
//If does not end with slash we should redirect
if (!req.getRequestURI().endsWith("/" ))
{
resp.sendRedirect(req.getRequestURI() + "/");
return;
}
Status collectionStatus = results.get(0);
resp.setDateHeader(LAST_MODIFIED, collectionStatus.getLastModified());
resp.setStatus(HttpServletResponse.SC_OK);
IndexWriter.write(results, context, resp, withBody);
}
else
{
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentLength((int)status.getContentLength());
resp.setContentType(status.getContentType());
resp.setDateHeader(LAST_MODIFIED, status.getLastModified());
if (withBody)
{
repositoryManager.read(context, resp.getOutputStream());
}
}
}
else
{
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
}

View File

@ -179,6 +179,10 @@
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-webdav</artifactId>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>

View File

@ -13,9 +13,7 @@
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.archiva</groupId>
@ -35,6 +33,7 @@
<module>archiva-webdav</module>
<module>archiva-rss</module>
<module>archiva-xmlrpc</module>
<module>archiva-repository-servlet</module>
</modules>
<profiles>
@ -45,4 +44,4 @@
</modules>
</profile>
</profiles>
</project>
</project>

19
pom.xml
View File

@ -401,6 +401,16 @@
<artifactId>archiva-transaction</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository-api</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-docs</artifactId>
@ -419,6 +429,11 @@
<artifactId>archiva-xml-tools</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-repository-servlet</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-webdav</artifactId>
@ -468,7 +483,7 @@
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
@ -483,7 +498,7 @@
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.2</version>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>