[MRM-815] aggregate indices for repository groups.

add a unit for this feature.

git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1199337 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Olivier Lamy 2011-11-08 16:48:35 +00:00
parent 6a767ceb44
commit f21e64d0c9
19 changed files with 562 additions and 33 deletions

View File

@ -0,0 +1,55 @@
<?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.
-->
<settings>
<profiles>
<profile>
<id>it-repo</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>local.central</id>
<url>@localRepositoryUrl@</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>local.central</id>
<url>@localRepositoryUrl@</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</settings>

View File

@ -19,8 +19,12 @@ package org.apache.archiva;
*/
import junit.framework.TestCase;
import org.apache.archiva.rest.api.services.ManagedRepositoriesService;
import org.apache.archiva.rest.api.services.ProxyConnectorService;
import org.apache.archiva.rest.api.services.RemoteRepositoriesService;
import org.apache.archiva.rest.api.services.RepositoriesService;
import org.apache.archiva.rest.api.services.RepositoryGroupService;
import org.apache.archiva.rest.api.services.SearchService;
import org.apache.archiva.webdav.RepositoryServlet;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.common.util.Base64Utility;
@ -76,10 +80,7 @@ public abstract class AbstractDownloadTest
}
protected String getSpringConfigLocation()
{
return "classpath*:META-INF/spring-context.xml classpath*:spring-context-artifacts-download.xml";
}
protected abstract String getSpringConfigLocation();
protected String getRestServicesPath()
@ -134,7 +135,6 @@ public abstract class AbstractDownloadTest
}
protected abstract Class getServletClass();
@After
public void tearDown()
@ -171,6 +171,51 @@ public abstract class AbstractDownloadTest
return service;
}
protected ManagedRepositoriesService getManagedRepositoriesService()
{
ManagedRepositoriesService service =
JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
ManagedRepositoriesService.class );
WebClient.client( service ).header( "Authorization", authorizationHeader );
WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000L );
return service;
}
protected RepositoryGroupService getRepositoryGroupService()
{
RepositoryGroupService service =
JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
RepositoryGroupService.class );
WebClient.client( service ).header( "Authorization", authorizationHeader );
WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000L );
return service;
}
protected RepositoriesService getRepositoriesService()
{
RepositoriesService service =
JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
RepositoriesService.class );
WebClient.client( service ).header( "Authorization", authorizationHeader );
WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000L );
return service;
}
protected SearchService getSearchService()
{
SearchService service =
JAXRSClientFactory.create( getBaseUrl() + "/" + getRestServicesPath() + "/archivaServices/",
SearchService.class );
WebClient.client( service ).header( "Authorization", authorizationHeader );
WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000L );
return service;
}
protected String getBaseUrl()
{
String baseUrlSysProps = System.getProperty( "archiva.baseRestUrl" );
@ -216,4 +261,5 @@ public abstract class AbstractDownloadTest
"http://localhost:" + port + "/" + getRestServicesPath() + "/fakeCreateAdminService/",
FakeCreateAdminService.class );
}
}

View File

@ -78,6 +78,11 @@ public class DownloadArtifactsTest
System.setProperty( "appserver.base", previousAppServerBase );
}
protected String getSpringConfigLocation()
{
return "classpath*:META-INF/spring-context.xml classpath*:spring-context-artifacts-download.xml";
}
@Before
public void startServer()
throws Exception
@ -87,7 +92,7 @@ public class DownloadArtifactsTest
//redirect handler
this.redirectServer = new Server( 0 );
ServletHolder shRedirect = new ServletHolder( getServletClass() );
ServletHolder shRedirect = new ServletHolder( RedirectServlet.class );
ServletContextHandler contextRedirect = new ServletContextHandler();
contextRedirect.setContextPath( "/" );
@ -173,11 +178,6 @@ public class DownloadArtifactsTest
return Collections.emptyList();
}
@Override
protected Class getServletClass()
{
return RedirectServlet.class;
}
public static class RedirectServlet
extends HttpServlet

View File

@ -18,16 +18,147 @@ package org.apache.archiva;
* under the License.
*/
import junit.framework.TestCase;
import org.apache.archiva.admin.model.beans.ManagedRepository;
import org.apache.archiva.admin.model.beans.ProxyConnector;
import org.apache.archiva.admin.model.beans.RemoteRepository;
import org.apache.archiva.admin.model.beans.RepositoryGroup;
import org.apache.archiva.rest.api.model.Artifact;
import org.apache.archiva.rest.api.model.SearchRequest;
import org.apache.archiva.rest.api.services.ManagedRepositoriesService;
import org.apache.archiva.rest.api.services.ProxyConnectorService;
import org.apache.archiva.rest.api.services.RepositoriesService;
import org.apache.archiva.rest.api.services.RepositoryGroupService;
import org.apache.archiva.rest.api.services.SearchService;
import org.codehaus.redback.integration.security.role.RedbackRoleConstants;
import org.codehaus.redback.rest.services.FakeCreateAdminService;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Arrays;
import java.util.List;
/**
* @author Olivier Lamy
*/
@RunWith( JUnit4.class )
public class DownloadMergedIndexTest
extends TestCase
extends AbstractDownloadTest
{
@BeforeClass
public static void setAppServerBase()
{
previousAppServerBase = System.getProperty( "appserver.base" );
System.setProperty( "appserver.base", "target/" + DownloadMergedIndexTest.class.getName() );
}
@AfterClass
public static void resetAppServerBase()
{
System.setProperty( "appserver.base", previousAppServerBase );
}
protected String getSpringConfigLocation()
{
return "classpath*:META-INF/spring-context.xml classpath*:spring-context-merge-index-download.xml";
}
@Test
public void downloadMergedIndex()
throws Exception
{
String id = Long.toString( System.currentTimeMillis() );
ManagedRepository managedRepository = new ManagedRepository();
managedRepository.setId( id );
managedRepository.setName( "name of " + id );
managedRepository.setLocation( "src/test/repositories/test-repo" );
managedRepository.setIndexDirectory( "target/tmpIndex/" + id );
ManagedRepositoriesService managedRepositoriesService = getManagedRepositoriesService();
if ( managedRepositoriesService.getManagedRepository( id ) != null )
{
managedRepositoriesService.deleteManagedRepository( id, false );
}
getManagedRepositoriesService().addManagedRepository( managedRepository );
RepositoriesService repositoriesService = getRepositoriesService();
repositoriesService.scanRepositoryNow( id, true );
// wait a bit to ensure index is finished
int timeout = 20000;
while ( timeout > 0 && repositoriesService.alreadyScanning( id ) )
{
Thread.sleep( 500 );
timeout -= 500;
}
RepositoryGroupService repositoryGroupService = getRepositoryGroupService();
RepositoryGroup repositoryGroup = new RepositoryGroup();
repositoryGroup.setId( "test-group" );
repositoryGroup.setRepositories( Arrays.asList( id ) );
repositoryGroupService.addRepositoryGroup( repositoryGroup );
// create a repo with a remote on the one with index
id = Long.toString( System.currentTimeMillis() );
managedRepository = new ManagedRepository();
managedRepository.setId( id );
managedRepository.setName( "name of " + id );
managedRepository.setLocation( "src/test/repositories/test-repo" );
managedRepository.setIndexDirectory( "target/tmpIndex/" + id );
if ( managedRepositoriesService.getManagedRepository( id ) != null )
{
managedRepositoriesService.deleteManagedRepository( id, false );
}
getManagedRepositoriesService().addManagedRepository( managedRepository );
RemoteRepository remoteRepository = new RemoteRepository();
remoteRepository.setId( "all-merged" );
remoteRepository.setName( "all-merged" );
remoteRepository.setDownloadRemoteIndex( true );
remoteRepository.setUrl( "http://localhost:" + port + "/repository/test-group" );
remoteRepository.setRemoteIndexUrl( "http://localhost:" + port + "/repository/test-group/.indexer" );
remoteRepository.setUserName( RedbackRoleConstants.ADMINISTRATOR_ACCOUNT_NAME );
remoteRepository.setPassword( FakeCreateAdminService.ADMIN_TEST_PWD );
getRemoteRepositoriesService().addRemoteRepository( remoteRepository );
ProxyConnectorService proxyConnectorService = getProxyConnectorService();
ProxyConnector proxyConnector = new ProxyConnector();
proxyConnector.setProxyId( "foo-bar" );
proxyConnector.setSourceRepoId( id );
proxyConnector.setTargetRepoId( "all-merged" );
proxyConnectorService.addProxyConnector( proxyConnector );
repositoriesService.scheduleDownloadRemoteIndex( "all-merged", true, true );
// wait a bit
timeout = 20000;
while ( timeout > 0 )
{
Thread.sleep( 500 );
timeout -= 500;
}
SearchService searchService = getSearchService();
SearchRequest request = new SearchRequest( );
request.setRepositories( Arrays.asList( id ) );
request.setGroupId( "org.apache.felix" );
List<Artifact> artifacts = searchService.searchArtifacts( request );
assertFalse( artifacts.isEmpty() );
assertEquals( 1, artifacts.size() );
}
}

View File

@ -0,0 +1,28 @@
<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>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-search</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Archiva Search</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
<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>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-test</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>archiva-test</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
<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>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-test</artifactId>
<packaging>jar</packaging>
<version>2.0</version>
<name>Archiva Test</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
<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>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-webapp</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>Archiva Webapp</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,138 @@
<!--
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.felix</groupId>
<artifactId>felix-parent</artifactId>
<version>2.1</version>
<relativePath>../pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>bundle</packaging>
<name>Apache Felix Bundle Repository</name>
<description>Bundle repository service.</description>
<artifactId>org.apache.felix.bundlerepository</artifactId>
<version>1.6.6</version>
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-1.6.6</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-1.6.6</developerConnection>
<url>http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-1.6.6</url>
</scm>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>org.apache.felix.utils</artifactId>
<version>1.1.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>org.osgi.service.obr</artifactId>
<version>1.0.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>org.apache.felix.shell</artifactId>
<version>1.4.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sf.kxml</groupId>
<artifactId>kxml2</artifactId>
<version>2.3.0</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>xmlpull</groupId>
<artifactId>xmlpull</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.0.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.0.7</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>org.apache.felix.bundlerepository;version="2.0"</Export-Package>
<Private-Package>
org.kxml2.io,
org.xmlpull.v1,
org.apache.felix.bundlerepository.impl.*,
org.apache.felix.utils.*
</Private-Package>
<Import-Package>!javax.xml.parsers,!org.xml.sax,org.osgi.service.log;resolution:=optional,org.osgi.service.obr;resolution:=optional,javax.xml.stream;resolution:=optional,*</Import-Package>
<DynamicImport-Package>org.apache.felix.shell</DynamicImport-Package>
<Bundle-Activator>${project.artifactId}.impl.Activator</Bundle-Activator>
<Bundle-DocURL>http://felix.apache.org/site/apache-felix-osgi-bundle-repository.html</Bundle-DocURL>
<Bundle-Url>http://felix.apache.org/site/downloads.cgi</Bundle-Url>
<Bundle-Source>http://felix.apache.org/site/downloads.cgi</Bundle-Source>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
<Export-Service>org.apache.felix.bundlerepository.RepositoryAdmin,org.osgi.service.obr.RepositoryAdmin</Export-Service>
<_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
<Include-Resource>META-INF/LICENSE=LICENSE,META-INF/LICENSE.kxml2=LICENSE.kxml2,META-INF/NOTICE=NOTICE,META-INF/DEPENDENCIES=DEPENDENCIES</Include-Resource>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<configuration>
<excludeSubProjects>false</excludeSubProjects>
<useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
<useMavenDefaultExcludes>true</useMavenDefaultExcludes>
<excludes>
<param>doc/*</param>
<param>maven-eclipse.xml</param>
<param>.checkstyle</param>
<param>.externalToolBuilders/*</param>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,54 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-lazy-init="true">
<context:property-placeholder system-properties-mode="OVERRIDE"/>
<bean name="commons-configuration" class="org.codehaus.redback.components.registry.commons.CommonsConfigurationRegistry">
<property name="properties">
<value>
<![CDATA[
<configuration>
<system/>
<xml fileName="${appserver.base}/conf/archiva-test-merge-index-download.xml" config-optional="true"
config-name="org.apache.archiva.base"
config-at="org.apache.archiva"/>
<properties fileName="${appserver.base}/conf/security.properties" config-optional="true"
config-at="org.codehaus.plexus.redback"/>
<properties fileName="org/apache/archiva/security.properties" config-at="org.codehaus.plexus.redback"/>
</configuration>
]]>
</value>
</property>
</bean>
</beans>

View File

@ -19,18 +19,17 @@ package org.apache.archiva.web.xmlrpc.api;
* under the License.
*/
import java.util.Date;
import java.util.List;
import com.atlassian.xmlrpc.ServiceObject;
import org.apache.archiva.web.xmlrpc.api.beans.Artifact;
import org.apache.archiva.web.xmlrpc.api.beans.Dependency;
import com.atlassian.xmlrpc.ServiceObject;
import java.util.Date;
import java.util.List;
@ServiceObject("SearchService")
@ServiceObject( "SearchService" )
public interface SearchService
{
/*
/*
* quick/general text search which returns a list of artifacts
* query for an artifact based on a checksum
* query for all available versions of an artifact, sorted in version significance order
@ -40,21 +39,25 @@ public interface SearchService
* query for all artifacts that depend on a given artifact
*/
public List<Artifact> quickSearch( String queryString )
throws Exception;
public List<Artifact> quickSearch( String queryString )
throws Exception;
public List<Artifact> getArtifactByChecksum( String checksum) throws Exception;
public List<Artifact> getArtifactVersions( String groupId, String artifactId ) throws Exception;
public List<Artifact> getArtifactVersionsByDate( String groupId, String artifactId, String version, Date whenGathered )
throws Exception;
public List<Artifact> getArtifactByChecksum( String checksum )
throws Exception;
public List<Artifact> getArtifactVersions( String groupId, String artifactId )
throws Exception;
public List<Artifact> getArtifactVersionsByDate( String groupId, String artifactId, String version,
Date whenGathered )
throws Exception;
public List<Dependency> getDependencies( String groupId, String artifactId, String version )
throws Exception;
public List<Artifact> getDependencyTree( String groupId, String artifactId, String version )
throws Exception;
public List<Dependency> getDependencies( String groupId, String artifactId, String version )
throws Exception;
public List<Artifact> getDependencyTree( String groupId, String artifactId, String version ) throws Exception;
public List<Artifact> getDependees( String groupId, String artifactId, String version )
throws Exception;
throws Exception;
}