http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java ---------------------------------------------------------------------- diff --git a/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java b/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java deleted file mode 100644 index 6c4e361..0000000 --- a/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java +++ /dev/null @@ -1,554 +0,0 @@ -package org.eclipse.aether.transport.file; - -/* - * 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 static org.junit.Assert.*; - -import java.io.File; -import java.io.FileNotFoundException; -import java.net.URI; - -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.TestLoggerFactory; -import org.eclipse.aether.internal.test.util.TestUtils; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.transport.GetTask; -import org.eclipse.aether.spi.connector.transport.PeekTask; -import org.eclipse.aether.spi.connector.transport.PutTask; -import org.eclipse.aether.spi.connector.transport.Transporter; -import org.eclipse.aether.spi.connector.transport.TransporterFactory; -import org.eclipse.aether.transfer.NoTransporterException; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - */ -public class FileTransporterTest -{ - - private DefaultRepositorySystemSession session; - - private TransporterFactory factory; - - private Transporter transporter; - - private File repoDir; - - private RemoteRepository newRepo( String url ) - { - return new RemoteRepository.Builder( "test", "default", url ).build(); - } - - private void newTransporter( String url ) - throws Exception - { - if ( transporter != null ) - { - transporter.close(); - transporter = null; - } - transporter = factory.newInstance( session, newRepo( url ) ); - } - - @Before - public void setUp() - throws Exception - { - session = TestUtils.newSession(); - factory = new FileTransporterFactory( new TestLoggerFactory() ); - repoDir = TestFileUtils.createTempDir(); - TestFileUtils.writeString( new File( repoDir, "file.txt" ), "test" ); - TestFileUtils.writeString( new File( repoDir, "empty.txt" ), "" ); - TestFileUtils.writeString( new File( repoDir, "some space.txt" ), "space" ); - newTransporter( repoDir.toURI().toString() ); - } - - @After - public void tearDown() - { - if ( transporter != null ) - { - transporter.close(); - transporter = null; - } - factory = null; - session = null; - } - - @Test - public void testClassify() - throws Exception - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( new FileNotFoundException() ) ); - assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( new ResourceNotFoundException( "test" ) ) ); - } - - @Test - public void testPeek() - throws Exception - { - transporter.peek( new PeekTask( URI.create( "file.txt" ) ) ); - } - - @Test - public void testPeek_NotFound() - throws Exception - { - try - { - transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); - fail( "Expected error" ); - } - catch ( ResourceNotFoundException e ) - { - assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); - } - } - - @Test - public void testPeek_Closed() - throws Exception - { - transporter.close(); - try - { - transporter.peek( new PeekTask( URI.create( "missing.txt" ) ) ); - fail( "Expected error" ); - } - catch ( IllegalStateException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - } - - @Test - public void testGet_ToMemory() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); - transporter.get( task ); - assertEquals( "test", task.getDataString() ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 4, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); - assertEquals( task.getDataString(), listener.baos.toString( "UTF-8" ) ); - } - - @Test - public void testGet_ToFile() - throws Exception - { - File file = TestFileUtils.createTempFile( "failure" ); - RecordingTransportListener listener = new RecordingTransportListener(); - GetTask task = new GetTask( URI.create( "file.txt" ) ).setDataFile( file ).setListener( listener ); - transporter.get( task ); - assertEquals( "test", TestFileUtils.readString( file ) ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 4, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); - assertEquals( "test", listener.baos.toString( "UTF-8" ) ); - } - - @Test - public void testGet_EmptyResource() - throws Exception - { - File file = TestFileUtils.createTempFile( "failure" ); - RecordingTransportListener listener = new RecordingTransportListener(); - GetTask task = new GetTask( URI.create( "empty.txt" ) ).setDataFile( file ).setListener( listener ); - transporter.get( task ); - assertEquals( "", TestFileUtils.readString( file ) ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 0, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertEquals( 0, listener.progressedCount ); - assertEquals( "", listener.baos.toString( "UTF-8" ) ); - } - - @Test - public void testGet_EncodedResourcePath() - throws Exception - { - GetTask task = new GetTask( URI.create( "some%20space.txt" ) ); - transporter.get( task ); - assertEquals( "space", task.getDataString() ); - } - - @Test - public void testGet_Fragment() - throws Exception - { - GetTask task = new GetTask( URI.create( "file.txt#ignored" ) ); - transporter.get( task ); - assertEquals( "test", task.getDataString() ); - } - - @Test - public void testGet_Query() - throws Exception - { - GetTask task = new GetTask( URI.create( "file.txt?ignored" ) ); - transporter.get( task ); - assertEquals( "test", task.getDataString() ); - } - - @Test - public void testGet_FileHandleLeak() - throws Exception - { - for ( int i = 0; i < 100; i++ ) - { - File file = TestFileUtils.createTempFile( "failure" ); - transporter.get( new GetTask( URI.create( "file.txt" ) ).setDataFile( file ) ); - assertTrue( i + ", " + file.getAbsolutePath(), file.delete() ); - } - } - - @Test - public void testGet_NotFound() - throws Exception - { - try - { - transporter.get( new GetTask( URI.create( "missing.txt" ) ) ); - fail( "Expected error" ); - } - catch ( ResourceNotFoundException e ) - { - assertEquals( Transporter.ERROR_NOT_FOUND, transporter.classify( e ) ); - } - } - - @Test - public void testGet_Closed() - throws Exception - { - transporter.close(); - try - { - transporter.get( new GetTask( URI.create( "file.txt" ) ) ); - fail( "Expected error" ); - } - catch ( IllegalStateException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - } - - @Test - public void testGet_StartCancelled() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - listener.cancelStart = true; - GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); - try - { - transporter.get( task ); - fail( "Expected error" ); - } - catch ( TransferCancelledException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - assertEquals( 0, listener.dataOffset ); - assertEquals( 4, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertEquals( 0, listener.progressedCount ); - } - - @Test - public void testGet_ProgressCancelled() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - listener.cancelProgress = true; - GetTask task = new GetTask( URI.create( "file.txt" ) ).setListener( listener ); - try - { - transporter.get( task ); - fail( "Expected error" ); - } - catch ( TransferCancelledException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - assertEquals( 0, listener.dataOffset ); - assertEquals( 4, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertEquals( 1, listener.progressedCount ); - } - - @Test - public void testPut_FromMemory() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); - transporter.put( task ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 6, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); - assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); - } - - @Test - public void testPut_FromFile() - throws Exception - { - File file = TestFileUtils.createTempFile( "upload" ); - RecordingTransportListener listener = new RecordingTransportListener(); - PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataFile( file ); - transporter.put( task ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 6, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); - assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); - } - - @Test - public void testPut_EmptyResource() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ); - transporter.put( task ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 0, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertEquals( 0, listener.progressedCount ); - assertEquals( "", TestFileUtils.readString( new File( repoDir, "file.txt" ) ) ); - } - - @Test - public void testPut_NonExistentParentDir() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - PutTask task = - new PutTask( URI.create( "dir/sub/dir/file.txt" ) ).setListener( listener ).setDataString( "upload" ); - transporter.put( task ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 6, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); - assertEquals( "upload", TestFileUtils.readString( new File( repoDir, "dir/sub/dir/file.txt" ) ) ); - } - - @Test - public void testPut_EncodedResourcePath() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - PutTask task = new PutTask( URI.create( "some%20space.txt" ) ).setListener( listener ).setDataString( "OK" ); - transporter.put( task ); - assertEquals( 0, listener.dataOffset ); - assertEquals( 2, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertTrue( "Count: " + listener.progressedCount, listener.progressedCount > 0 ); - assertEquals( "OK", TestFileUtils.readString( new File( repoDir, "some space.txt" ) ) ); - } - - @Test - public void testPut_FileHandleLeak() - throws Exception - { - for ( int i = 0; i < 100; i++ ) - { - File src = TestFileUtils.createTempFile( "upload" ); - File dst = new File( repoDir, "file.txt" ); - transporter.put( new PutTask( URI.create( "file.txt" ) ).setDataFile( src ) ); - assertTrue( i + ", " + src.getAbsolutePath(), src.delete() ); - assertTrue( i + ", " + dst.getAbsolutePath(), dst.delete() ); - } - } - - @Test - public void testPut_Closed() - throws Exception - { - transporter.close(); - try - { - transporter.put( new PutTask( URI.create( "missing.txt" ) ) ); - fail( "Expected error" ); - } - catch ( IllegalStateException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - } - - @Test - public void testPut_StartCancelled() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - listener.cancelStart = true; - PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); - try - { - transporter.put( task ); - fail( "Expected error" ); - } - catch ( TransferCancelledException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - assertEquals( 0, listener.dataOffset ); - assertEquals( 6, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertEquals( 0, listener.progressedCount ); - assertFalse( new File( repoDir, "file.txt" ).exists() ); - } - - @Test - public void testPut_ProgressCancelled() - throws Exception - { - RecordingTransportListener listener = new RecordingTransportListener(); - listener.cancelProgress = true; - PutTask task = new PutTask( URI.create( "file.txt" ) ).setListener( listener ).setDataString( "upload" ); - try - { - transporter.put( task ); - fail( "Expected error" ); - } - catch ( TransferCancelledException e ) - { - assertEquals( Transporter.ERROR_OTHER, transporter.classify( e ) ); - } - assertEquals( 0, listener.dataOffset ); - assertEquals( 6, listener.dataLength ); - assertEquals( 1, listener.startedCount ); - assertEquals( 1, listener.progressedCount ); - assertFalse( new File( repoDir, "file.txt" ).exists() ); - } - - @Test( expected = NoTransporterException.class ) - public void testInit_BadProtocol() - throws Exception - { - newTransporter( "bad:/void" ); - } - - @Test - public void testInit_CaseInsensitiveProtocol() - throws Exception - { - newTransporter( "file:/void" ); - newTransporter( "FILE:/void" ); - newTransporter( "File:/void" ); - } - - @Test - public void testInit_OpaqueUrl() - throws Exception - { - testInit( "file:repository", "repository" ); - } - - @Test - public void testInit_OpaqueUrlTrailingSlash() - throws Exception - { - testInit( "file:repository/", "repository" ); - } - - @Test - public void testInit_OpaqueUrlSpaces() - throws Exception - { - testInit( "file:repo%20space", "repo space" ); - } - - @Test - public void testInit_OpaqueUrlSpacesDecoded() - throws Exception - { - testInit( "file:repo space", "repo space" ); - } - - @Test - public void testInit_HierarchicalUrl() - throws Exception - { - testInit( "file:/repository", "/repository" ); - } - - @Test - public void testInit_HierarchicalUrlTrailingSlash() - throws Exception - { - testInit( "file:/repository/", "/repository" ); - } - - @Test - public void testInit_HierarchicalUrlSpaces() - throws Exception - { - testInit( "file:/repo%20space", "/repo space" ); - } - - @Test - public void testInit_HierarchicalUrlSpacesDecoded() - throws Exception - { - testInit( "file:/repo space", "/repo space" ); - } - - @Test - public void testInit_HierarchicalUrlRoot() - throws Exception - { - testInit( "file:/", "/" ); - } - - @Test - public void testInit_HierarchicalUrlHostNoPath() - throws Exception - { - testInit( "file://host/", "/" ); - } - - @Test - public void testInit_HierarchicalUrlHostPath() - throws Exception - { - testInit( "file://host/dir", "/dir" ); - } - - private void testInit( String base, String expected ) - throws Exception - { - newTransporter( base ); - File exp = new File( expected ).getAbsoluteFile(); - assertEquals( exp, ( (FileTransporter) transporter ).getBasedir() ); - } - -}
http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java ---------------------------------------------------------------------- diff --git a/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java b/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java deleted file mode 100644 index c6331e0..0000000 --- a/aether-transport-file/src/test/java/org/eclipse/aether/transport/file/RecordingTransportListener.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.eclipse.aether.transport.file; - -/* - * 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.ByteArrayOutputStream; -import java.nio.ByteBuffer; - -import org.eclipse.aether.spi.connector.transport.TransportListener; -import org.eclipse.aether.transfer.TransferCancelledException; - -class RecordingTransportListener - extends TransportListener -{ - - public final ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 ); - - public long dataOffset; - - public long dataLength; - - public int startedCount; - - public int progressedCount; - - public boolean cancelStart; - - public boolean cancelProgress; - - @Override - public void transportStarted( long dataOffset, long dataLength ) - throws TransferCancelledException - { - startedCount++; - progressedCount = 0; - this.dataLength = dataLength; - this.dataOffset = dataOffset; - baos.reset(); - if ( cancelStart ) - { - throw new TransferCancelledException(); - } - } - - @Override - public void transportProgressed( ByteBuffer data ) - throws TransferCancelledException - { - progressedCount++; - baos.write( data.array(), data.arrayOffset() + data.position(), data.remaining() ); - if ( cancelProgress ) - { - throw new TransferCancelledException(); - } - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/pom.xml ---------------------------------------------------------------------- diff --git a/aether-transport-http/pom.xml b/aether-transport-http/pom.xml deleted file mode 100644 index cd2e7b3..0000000 --- a/aether-transport-http/pom.xml +++ /dev/null @@ -1,118 +0,0 @@ -<?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/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.apache.maven.aether</groupId> - <artifactId>aether</artifactId> - <version>1.0.3-SNAPSHOT</version> - </parent> - - <artifactId>aether-transport-http</artifactId> - - <name>Aether Transport HTTP</name> - <description> - A transport implementation for repositories using http:// and https:// URLs. - </description> - - <dependencies> - <dependency> - <groupId>org.apache.maven.aether</groupId> - <artifactId>aether-api</artifactId> - </dependency> - <dependency> - <groupId>org.apache.maven.aether</groupId> - <artifactId>aether-spi</artifactId> - </dependency> - <dependency> - <groupId>org.apache.maven.aether</groupId> - <artifactId>aether-util</artifactId> - </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - <version>4.2.6</version> - <exclusions> - <exclusion> - <!-- using jcl-over-slf4j instead --> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>jcl-over-slf4j</artifactId> - <version>1.6.2</version> - </dependency> - <dependency> - <groupId>javax.inject</groupId> - <artifactId>javax.inject</artifactId> - <scope>provided</scope> - <optional>true</optional> - </dependency> - <dependency> - <groupId>org.sonatype.sisu</groupId> - <artifactId>sisu-guice</artifactId> - <classifier>no_aop</classifier> - <scope>test</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-library</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.maven.aether</groupId> - <artifactId>aether-test-util</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>7.6.14.v20131031</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - <version>1.0.7</version> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.eclipse.sisu</groupId> - <artifactId>sisu-maven-plugin</artifactId> - </plugin> - </plugins> - </build> -</project> http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java deleted file mode 100644 index 9b86252..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/AuthSchemePool.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.LinkedList; - -import org.apache.http.auth.AuthScheme; -import org.apache.http.client.params.AuthPolicy; -import org.apache.http.impl.auth.BasicScheme; - -/** - * Pool of (equivalent) auth schemes for a single host. - */ -final class AuthSchemePool -{ - - private final LinkedList<AuthScheme> authSchemes; - - private String schemeName; - - public AuthSchemePool() - { - authSchemes = new LinkedList<AuthScheme>(); - } - - public synchronized AuthScheme get() - { - AuthScheme authScheme = null; - if ( !authSchemes.isEmpty() ) - { - authScheme = authSchemes.removeLast(); - } - else if ( AuthPolicy.BASIC.equalsIgnoreCase( schemeName ) ) - { - authScheme = new BasicScheme(); - } - return authScheme; - } - - public synchronized void put( AuthScheme authScheme ) - { - if ( authScheme == null ) - { - return; - } - if ( !authScheme.getSchemeName().equals( schemeName ) ) - { - schemeName = authScheme.getSchemeName(); - authSchemes.clear(); - } - authSchemes.add( authScheme ); - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java deleted file mode 100644 index c0daeaf..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DeferredCredentialsProvider.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.NTCredentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.eclipse.aether.repository.AuthenticationContext; - -/** - * Credentials provider that defers calls into the auth context until authentication is actually requested. - */ -final class DeferredCredentialsProvider - implements CredentialsProvider -{ - - private final CredentialsProvider delegate; - - private final Map<AuthScope, Factory> factories; - - public DeferredCredentialsProvider() - { - delegate = new BasicCredentialsProvider(); - factories = new HashMap<AuthScope, Factory>(); - } - - public void setCredentials( AuthScope authScope, Factory factory ) - { - factories.put( authScope, factory ); - } - - public void setCredentials( AuthScope authScope, Credentials credentials ) - { - delegate.setCredentials( authScope, credentials ); - } - - public Credentials getCredentials( AuthScope authScope ) - { - synchronized ( factories ) - { - for ( Iterator<Map.Entry<AuthScope, Factory>> it = factories.entrySet().iterator(); it.hasNext(); ) - { - Map.Entry<AuthScope, Factory> entry = it.next(); - if ( authScope.match( entry.getKey() ) >= 0 ) - { - it.remove(); - delegate.setCredentials( entry.getKey(), entry.getValue().newCredentials() ); - } - } - } - return delegate.getCredentials( authScope ); - } - - public void clear() - { - delegate.clear(); - } - - interface Factory - { - - Credentials newCredentials(); - - } - - static class BasicFactory - implements Factory - { - - private final AuthenticationContext authContext; - - public BasicFactory( AuthenticationContext authContext ) - { - this.authContext = authContext; - } - - public Credentials newCredentials() - { - String username = authContext.get( AuthenticationContext.USERNAME ); - if ( username == null ) - { - return null; - } - String password = authContext.get( AuthenticationContext.PASSWORD ); - return new UsernamePasswordCredentials( username, password ); - } - - } - - static class NtlmFactory - implements Factory - { - - private final AuthenticationContext authContext; - - public NtlmFactory( AuthenticationContext authContext ) - { - this.authContext = authContext; - } - - public Credentials newCredentials() - { - String username = authContext.get( AuthenticationContext.USERNAME ); - if ( username == null ) - { - return null; - } - String password = authContext.get( AuthenticationContext.PASSWORD ); - String domain = authContext.get( AuthenticationContext.NTLM_DOMAIN ); - String workstation = authContext.get( AuthenticationContext.NTLM_WORKSTATION ); - - if ( domain == null ) - { - int backslash = username.indexOf( '\\' ); - if ( backslash < 0 ) - { - domain = guessDomain(); - } - else - { - domain = username.substring( 0, backslash ); - username = username.substring( backslash + 1 ); - } - } - if ( workstation == null ) - { - workstation = guessWorkstation(); - } - - return new NTCredentials( username, password, workstation, domain ); - } - - private static String guessDomain() - { - return safeNtlmString( System.getProperty( "http.auth.ntlm.domain" ), System.getenv( "USERDOMAIN" ) ); - } - - private static String guessWorkstation() - { - String localHost = null; - try - { - localHost = InetAddress.getLocalHost().getHostName(); - } - catch ( UnknownHostException e ) - { - // well, we have other options to try - } - return safeNtlmString( System.getProperty( "http.auth.ntlm.host" ), System.getenv( "COMPUTERNAME" ), - localHost ); - } - - private static String safeNtlmString( String... strings ) - { - for ( String string : strings ) - { - if ( string != null ) - { - return string; - } - } - // avoid NPE from httpclient and trigger proper auth failure instead - return ""; - } - - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java deleted file mode 100644 index f16246e..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/DemuxCredentialsProvider.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.client.CredentialsProvider; - -/** - * Credentials provider that helps to isolate server from proxy credentials. Apache HttpClient uses a single provider - * for both server and proxy auth, using the auth scope (host, port, etc.) to select the proper credentials. With regard - * to redirects, we use an auth scope for server credentials that's not specific enough to not be mistaken for proxy - * auth. This provider helps to maintain the proper isolation. - */ -final class DemuxCredentialsProvider - implements CredentialsProvider -{ - - private final CredentialsProvider serverCredentialsProvider; - - private final CredentialsProvider proxyCredentialsProvider; - - private final HttpHost proxy; - - public DemuxCredentialsProvider( CredentialsProvider serverCredentialsProvider, - CredentialsProvider proxyCredentialsProvider, HttpHost proxy ) - { - this.serverCredentialsProvider = serverCredentialsProvider; - this.proxyCredentialsProvider = proxyCredentialsProvider; - this.proxy = proxy; - } - - private CredentialsProvider getDelegate( AuthScope authScope ) - { - if ( proxy.getPort() == authScope.getPort() && proxy.getHostName().equalsIgnoreCase( authScope.getHost() ) ) - { - return proxyCredentialsProvider; - } - return serverCredentialsProvider; - } - - public Credentials getCredentials( AuthScope authScope ) - { - return getDelegate( authScope ).getCredentials( authScope ); - } - - public void setCredentials( AuthScope authScope, Credentials credentials ) - { - getDelegate( authScope ).setCredentials( authScope, credentials ); - } - - public void clear() - { - serverCredentialsProvider.clear(); - proxyCredentialsProvider.clear(); - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java deleted file mode 100644 index b3a9d4b..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java +++ /dev/null @@ -1,215 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.Closeable; -import java.util.Arrays; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.http.HttpHost; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.impl.conn.PoolingClientConnectionManager; -import org.eclipse.aether.RepositoryCache; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.util.ConfigUtils; - -/** - * Container for HTTP-related state that can be shared across incarnations of the transporter to optimize the - * communication with servers. - */ -final class GlobalState - implements Closeable -{ - - static class CompoundKey - { - - private final Object[] keys; - - public CompoundKey( Object... keys ) - { - this.keys = keys; - } - - @Override - public boolean equals( Object obj ) - { - if ( this == obj ) - { - return true; - } - if ( obj == null || !getClass().equals( obj.getClass() ) ) - { - return false; - } - CompoundKey that = (CompoundKey) obj; - return Arrays.equals( keys, that.keys ); - } - - @Override - public int hashCode() - { - int hash = 17; - hash = hash * 31 + Arrays.hashCode( keys ); - return hash; - } - - @Override - public String toString() - { - return Arrays.toString( keys ); - } - } - - private static final String KEY = GlobalState.class.getName(); - - private static final String CONFIG_PROP_CACHE_STATE = "aether.connector.http.cacheState"; - - private final ConcurrentMap<SslConfig, ClientConnectionManager> connectionManagers; - - private final ConcurrentMap<CompoundKey, Object> userTokens; - - private final ConcurrentMap<HttpHost, AuthSchemePool> authSchemePools; - - private final ConcurrentMap<CompoundKey, Boolean> expectContinues; - - public static GlobalState get( RepositorySystemSession session ) - { - GlobalState cache; - RepositoryCache repoCache = session.getCache(); - if ( repoCache == null || !ConfigUtils.getBoolean( session, true, CONFIG_PROP_CACHE_STATE ) ) - { - cache = null; - } - else - { - Object tmp = repoCache.get( session, KEY ); - if ( tmp instanceof GlobalState ) - { - cache = (GlobalState) tmp; - } - else - { - synchronized ( GlobalState.class ) - { - tmp = repoCache.get( session, KEY ); - if ( tmp instanceof GlobalState ) - { - cache = (GlobalState) tmp; - } - else - { - cache = new GlobalState(); - repoCache.put( session, KEY, cache ); - } - } - } - } - return cache; - } - - private GlobalState() - { - connectionManagers = new ConcurrentHashMap<SslConfig, ClientConnectionManager>(); - userTokens = new ConcurrentHashMap<CompoundKey, Object>(); - authSchemePools = new ConcurrentHashMap<HttpHost, AuthSchemePool>(); - expectContinues = new ConcurrentHashMap<CompoundKey, Boolean>(); - } - - public void close() - { - for ( Iterator<Map.Entry<SslConfig, ClientConnectionManager>> it = connectionManagers.entrySet().iterator(); it.hasNext(); ) - { - ClientConnectionManager connMgr = it.next().getValue(); - it.remove(); - connMgr.shutdown(); - } - } - - public ClientConnectionManager getConnectionManager( SslConfig config ) - { - ClientConnectionManager manager = connectionManagers.get( config ); - if ( manager == null ) - { - ClientConnectionManager connMgr = newConnectionManager( config ); - manager = connectionManagers.putIfAbsent( config, connMgr ); - if ( manager != null ) - { - connMgr.shutdown(); - } - else - { - manager = connMgr; - } - } - return manager; - } - - public static ClientConnectionManager newConnectionManager( SslConfig sslConfig ) - { - SchemeRegistry schemeReg = new SchemeRegistry(); - schemeReg.register( new Scheme( "http", 80, new PlainSocketFactory() ) ); - schemeReg.register( new Scheme( "https", 443, new SslSocketFactory( sslConfig ) ) ); - - PoolingClientConnectionManager connMgr = new PoolingClientConnectionManager( schemeReg ); - connMgr.setMaxTotal( 100 ); - connMgr.setDefaultMaxPerRoute( 50 ); - return connMgr; - } - - public Object getUserToken( CompoundKey key ) - { - return userTokens.get( key ); - } - - public void setUserToken( CompoundKey key, Object userToken ) - { - if ( userToken != null ) - { - userTokens.put( key, userToken ); - } - else - { - userTokens.remove( key ); - } - } - - public ConcurrentMap<HttpHost, AuthSchemePool> getAuthSchemePools() - { - return authSchemePools; - } - - public Boolean getExpectContinue( CompoundKey key ) - { - return expectContinues.get( key ); - } - - public void setExpectContinue( CompoundKey key, boolean enabled ) - { - expectContinues.put( key, enabled ); - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java deleted file mode 100644 index 7a945ea..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpMkCol.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.net.URI; - -import org.apache.http.client.methods.HttpRequestBase; - -/** - * WebDAV MKCOL request to create parent directories. - */ -final class HttpMkCol - extends HttpRequestBase -{ - - public HttpMkCol( URI uri ) - { - setURI( uri ); - } - - @Override - public String getMethod() - { - return "MKCOL"; - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java deleted file mode 100644 index f0b0a6f..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java +++ /dev/null @@ -1,598 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.params.AuthParams; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.HttpClient; -import org.apache.http.client.HttpResponseException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpOptions; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.utils.URIUtils; -import org.apache.http.conn.params.ConnRouteParams; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.impl.client.DecompressingHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.cookie.DateUtils; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.util.EntityUtils; -import org.eclipse.aether.ConfigurationProperties; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.AuthenticationContext; -import org.eclipse.aether.repository.Proxy; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.transport.AbstractTransporter; -import org.eclipse.aether.spi.connector.transport.GetTask; -import org.eclipse.aether.spi.connector.transport.PeekTask; -import org.eclipse.aether.spi.connector.transport.PutTask; -import org.eclipse.aether.spi.connector.transport.TransportTask; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.transfer.NoTransporterException; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.util.ConfigUtils; - -/** - * A transporter for HTTP/HTTPS. - */ -final class HttpTransporter - extends AbstractTransporter -{ - - private static final Pattern CONTENT_RANGE_PATTERN = - Pattern.compile( "\\s*bytes\\s+([0-9]+)\\s*-\\s*([0-9]+)\\s*/.*" ); - - private final Logger logger; - - private final AuthenticationContext repoAuthContext; - - private final AuthenticationContext proxyAuthContext; - - private final URI baseUri; - - private final HttpHost server; - - private final HttpHost proxy; - - private final HttpClient client; - - private final Map<?, ?> headers; - - private final LocalState state; - - public HttpTransporter( RemoteRepository repository, RepositorySystemSession session, Logger logger ) - throws NoTransporterException - { - if ( !"http".equalsIgnoreCase( repository.getProtocol() ) - && !"https".equalsIgnoreCase( repository.getProtocol() ) ) - { - throw new NoTransporterException( repository ); - } - this.logger = logger; - try - { - baseUri = new URI( repository.getUrl() ).parseServerAuthority(); - if ( baseUri.isOpaque() ) - { - throw new URISyntaxException( repository.getUrl(), "URL must not be opaque" ); - } - server = URIUtils.extractHost( baseUri ); - if ( server == null ) - { - throw new URISyntaxException( repository.getUrl(), "URL lacks host name" ); - } - } - catch ( URISyntaxException e ) - { - throw new NoTransporterException( repository, e.getMessage(), e ); - } - proxy = toHost( repository.getProxy() ); - - repoAuthContext = AuthenticationContext.forRepository( session, repository ); - proxyAuthContext = AuthenticationContext.forProxy( session, repository ); - - state = new LocalState( session, repository, new SslConfig( session, repoAuthContext ) ); - - headers = - ConfigUtils.getMap( session, Collections.emptyMap(), ConfigurationProperties.HTTP_HEADERS + "." - + repository.getId(), ConfigurationProperties.HTTP_HEADERS ); - - DefaultHttpClient client = new DefaultHttpClient( state.getConnectionManager() ); - - configureClient( client.getParams(), session, repository, proxy ); - - client.setCredentialsProvider( toCredentialsProvider( server, repoAuthContext, proxy, proxyAuthContext ) ); - - this.client = new DecompressingHttpClient( client ); - } - - private static HttpHost toHost( Proxy proxy ) - { - HttpHost host = null; - if ( proxy != null ) - { - host = new HttpHost( proxy.getHost(), proxy.getPort() ); - } - return host; - } - - private static void configureClient( HttpParams params, RepositorySystemSession session, - RemoteRepository repository, HttpHost proxy ) - { - AuthParams.setCredentialCharset( params, - ConfigUtils.getString( session, - ConfigurationProperties.DEFAULT_HTTP_CREDENTIAL_ENCODING, - ConfigurationProperties.HTTP_CREDENTIAL_ENCODING + "." - + repository.getId(), - ConfigurationProperties.HTTP_CREDENTIAL_ENCODING ) ); - ConnRouteParams.setDefaultProxy( params, proxy ); - HttpConnectionParams.setConnectionTimeout( params, - ConfigUtils.getInteger( session, - ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT, - ConfigurationProperties.CONNECT_TIMEOUT - + "." + repository.getId(), - ConfigurationProperties.CONNECT_TIMEOUT ) ); - HttpConnectionParams.setSoTimeout( params, - ConfigUtils.getInteger( session, - ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT, - ConfigurationProperties.REQUEST_TIMEOUT + "." - + repository.getId(), - ConfigurationProperties.REQUEST_TIMEOUT ) ); - HttpProtocolParams.setUserAgent( params, ConfigUtils.getString( session, - ConfigurationProperties.DEFAULT_USER_AGENT, - ConfigurationProperties.USER_AGENT ) ); - } - - private static CredentialsProvider toCredentialsProvider( HttpHost server, AuthenticationContext serverAuthCtx, - HttpHost proxy, AuthenticationContext proxyAuthCtx ) - { - CredentialsProvider provider = toCredentialsProvider( server.getHostName(), AuthScope.ANY_PORT, serverAuthCtx ); - if ( proxy != null ) - { - CredentialsProvider p = toCredentialsProvider( proxy.getHostName(), proxy.getPort(), proxyAuthCtx ); - provider = new DemuxCredentialsProvider( provider, p, proxy ); - } - return provider; - } - - private static CredentialsProvider toCredentialsProvider( String host, int port, AuthenticationContext ctx ) - { - DeferredCredentialsProvider provider = new DeferredCredentialsProvider(); - if ( ctx != null ) - { - AuthScope basicScope = new AuthScope( host, port ); - provider.setCredentials( basicScope, new DeferredCredentialsProvider.BasicFactory( ctx ) ); - - AuthScope ntlmScope = new AuthScope( host, port, AuthScope.ANY_REALM, "ntlm" ); - provider.setCredentials( ntlmScope, new DeferredCredentialsProvider.NtlmFactory( ctx ) ); - } - return provider; - } - - LocalState getState() - { - return state; - } - - private URI resolve( TransportTask task ) - { - return UriUtils.resolve( baseUri, task.getLocation() ); - } - - public int classify( Throwable error ) - { - if ( error instanceof HttpResponseException - && ( (HttpResponseException) error ).getStatusCode() == HttpStatus.SC_NOT_FOUND ) - { - return ERROR_NOT_FOUND; - } - return ERROR_OTHER; - } - - @Override - protected void implPeek( PeekTask task ) - throws Exception - { - HttpHead request = commonHeaders( new HttpHead( resolve( task ) ) ); - execute( request, null ); - } - - @Override - protected void implGet( GetTask task ) - throws Exception - { - EntityGetter getter = new EntityGetter( task ); - HttpGet request = commonHeaders( new HttpGet( resolve( task ) ) ); - resume( request, task ); - try - { - execute( request, getter ); - } - catch ( HttpResponseException e ) - { - if ( e.getStatusCode() == HttpStatus.SC_PRECONDITION_FAILED && request.containsHeader( HttpHeaders.RANGE ) ) - { - request = commonHeaders( new HttpGet( request.getURI() ) ); - execute( request, getter ); - return; - } - throw e; - } - } - - @Override - protected void implPut( PutTask task ) - throws Exception - { - PutTaskEntity entity = new PutTaskEntity( task ); - HttpPut request = commonHeaders( entity( new HttpPut( resolve( task ) ), entity ) ); - try - { - execute( request, null ); - } - catch ( HttpResponseException e ) - { - if ( e.getStatusCode() == HttpStatus.SC_EXPECTATION_FAILED && request.containsHeader( HttpHeaders.EXPECT ) ) - { - state.setExpectContinue( false ); - request = commonHeaders( entity( new HttpPut( request.getURI() ), entity ) ); - execute( request, null ); - return; - } - throw e; - } - } - - private void execute( HttpUriRequest request, EntityGetter getter ) - throws Exception - { - try - { - SharingHttpContext context = new SharingHttpContext( state ); - prepare( request, context ); - HttpResponse response = client.execute( server, request, context ); - try - { - context.close(); - handleStatus( response ); - if ( getter != null ) - { - getter.handle( response ); - } - } - finally - { - EntityUtils.consumeQuietly( response.getEntity() ); - } - } - catch ( IOException e ) - { - if ( e.getCause() instanceof TransferCancelledException ) - { - throw (Exception) e.getCause(); - } - throw e; - } - } - - private void prepare( HttpUriRequest request, SharingHttpContext context ) - { - boolean put = HttpPut.METHOD_NAME.equalsIgnoreCase( request.getMethod() ); - if ( state.getWebDav() == null && ( put || isPayloadPresent( request ) ) ) - { - try - { - HttpOptions req = commonHeaders( new HttpOptions( request.getURI() ) ); - HttpResponse response = client.execute( server, req, context ); - state.setWebDav( isWebDav( response ) ); - EntityUtils.consumeQuietly( response.getEntity() ); - } - catch ( IOException e ) - { - logger.debug( "Failed to prepare HTTP context", e ); - } - } - if ( put && Boolean.TRUE.equals( state.getWebDav() ) ) - { - mkdirs( request.getURI(), context ); - } - } - - private boolean isWebDav( HttpResponse response ) - { - return response.containsHeader( HttpHeaders.DAV ); - } - - private void mkdirs( URI uri, SharingHttpContext context ) - { - List<URI> dirs = UriUtils.getDirectories( baseUri, uri ); - int index = 0; - for ( ; index < dirs.size(); index++ ) - { - try - { - HttpResponse response = - client.execute( server, commonHeaders( new HttpMkCol( dirs.get( index ) ) ), context ); - try - { - int status = response.getStatusLine().getStatusCode(); - if ( status < 300 || status == HttpStatus.SC_METHOD_NOT_ALLOWED ) - { - break; - } - else if ( status == HttpStatus.SC_CONFLICT ) - { - continue; - } - handleStatus( response ); - } - finally - { - EntityUtils.consumeQuietly( response.getEntity() ); - } - } - catch ( IOException e ) - { - logger.debug( "Failed to create parent directory " + dirs.get( index ), e ); - return; - } - } - for ( index--; index >= 0; index-- ) - { - try - { - HttpResponse response = - client.execute( server, commonHeaders( new HttpMkCol( dirs.get( index ) ) ), context ); - try - { - handleStatus( response ); - } - finally - { - EntityUtils.consumeQuietly( response.getEntity() ); - } - } - catch ( IOException e ) - { - logger.debug( "Failed to create parent directory " + dirs.get( index ), e ); - return; - } - } - } - - private <T extends HttpEntityEnclosingRequest> T entity( T request, HttpEntity entity ) - { - request.setEntity( entity ); - return request; - } - - private boolean isPayloadPresent( HttpUriRequest request ) - { - if ( request instanceof HttpEntityEnclosingRequest ) - { - HttpEntity entity = ( (HttpEntityEnclosingRequest) request ).getEntity(); - return entity != null && entity.getContentLength() != 0; - } - return false; - } - - private <T extends HttpUriRequest> T commonHeaders( T request ) - { - request.setHeader( HttpHeaders.CACHE_CONTROL, "no-cache, no-store" ); - request.setHeader( HttpHeaders.PRAGMA, "no-cache" ); - - if ( state.isExpectContinue() && isPayloadPresent( request ) ) - { - request.setHeader( HttpHeaders.EXPECT, "100-continue" ); - } - - for ( Map.Entry<?, ?> entry : headers.entrySet() ) - { - if ( !( entry.getKey() instanceof String ) ) - { - continue; - } - if ( entry.getValue() instanceof String ) - { - request.setHeader( entry.getKey().toString(), entry.getValue().toString() ); - } - else - { - request.removeHeaders( entry.getKey().toString() ); - } - } - - if ( !state.isExpectContinue() ) - { - request.removeHeaders( HttpHeaders.EXPECT ); - } - - return request; - } - - private <T extends HttpUriRequest> T resume( T request, GetTask task ) - { - long resumeOffset = task.getResumeOffset(); - if ( resumeOffset > 0 && task.getDataFile() != null ) - { - request.setHeader( HttpHeaders.RANGE, "bytes=" + Long.toString( resumeOffset ) + '-' ); - request.setHeader( HttpHeaders.IF_UNMODIFIED_SINCE, - DateUtils.formatDate( new Date( task.getDataFile().lastModified() - 60 * 1000 ) ) ); - request.setHeader( HttpHeaders.ACCEPT_ENCODING, "identity" ); - } - return request; - } - - private void handleStatus( HttpResponse response ) - throws HttpResponseException - { - int status = response.getStatusLine().getStatusCode(); - if ( status >= 300 ) - { - throw new HttpResponseException( status, response.getStatusLine().getReasonPhrase() + " (" + status + ")" ); - } - } - - @Override - protected void implClose() - { - AuthenticationContext.close( repoAuthContext ); - AuthenticationContext.close( proxyAuthContext ); - state.close(); - } - - private class EntityGetter - { - - private final GetTask task; - - public EntityGetter( GetTask task ) - { - this.task = task; - } - - public void handle( HttpResponse response ) - throws IOException, TransferCancelledException - { - HttpEntity entity = response.getEntity(); - if ( entity == null ) - { - entity = new ByteArrayEntity( new byte[0] ); - } - - long offset = 0, length = entity.getContentLength(); - String range = getHeader( response, HttpHeaders.CONTENT_RANGE ); - if ( range != null ) - { - Matcher m = CONTENT_RANGE_PATTERN.matcher( range ); - if ( !m.matches() ) - { - throw new IOException( "Invalid Content-Range header for partial download: " + range ); - } - offset = Long.parseLong( m.group( 1 ) ); - length = Long.parseLong( m.group( 2 ) ) + 1; - if ( offset < 0 || offset >= length || ( offset > 0 && offset != task.getResumeOffset() ) ) - { - throw new IOException( "Invalid Content-Range header for partial download from offset " - + task.getResumeOffset() + ": " + range ); - } - } - - InputStream is = entity.getContent(); - utilGet( task, is, true, length, offset > 0 ); - extractChecksums( response ); - } - - private void extractChecksums( HttpResponse response ) - { - // Nexus-style, ETag: "{SHA1{d40d68ba1f88d8e9b0040f175a6ff41928abd5e7}}" - String etag = getHeader( response, HttpHeaders.ETAG ); - if ( etag != null ) - { - int start = etag.indexOf( "SHA1{" ), end = etag.indexOf( "}", start + 5 ); - if ( start >= 0 && end > start ) - { - task.setChecksum( "SHA-1", etag.substring( start + 5, end ) ); - } - } - } - - private String getHeader( HttpResponse response, String name ) - { - Header header = response.getFirstHeader( name ); - return ( header != null ) ? header.getValue() : null; - } - - } - - private class PutTaskEntity - extends AbstractHttpEntity - { - - private final PutTask task; - - public PutTaskEntity( PutTask task ) - { - this.task = task; - } - - public boolean isRepeatable() - { - return true; - } - - public boolean isStreaming() - { - return false; - } - - public long getContentLength() - { - return task.getDataLength(); - } - - public InputStream getContent() - throws IOException - { - return task.newInputStream(); - } - - public void writeTo( OutputStream os ) - throws IOException - { - try - { - utilPut( task, os, false ); - } - catch ( TransferCancelledException e ) - { - throw (IOException) new InterruptedIOException().initCause( e ); - } - } - - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java deleted file mode 100644 index e9a9bfd..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporterFactory.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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 javax.inject.Inject; -import javax.inject.Named; - -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.spi.connector.transport.Transporter; -import org.eclipse.aether.spi.connector.transport.TransporterFactory; -import org.eclipse.aether.spi.locator.Service; -import org.eclipse.aether.spi.locator.ServiceLocator; -import org.eclipse.aether.spi.log.Logger; -import org.eclipse.aether.spi.log.LoggerFactory; -import org.eclipse.aether.spi.log.NullLoggerFactory; -import org.eclipse.aether.transfer.NoTransporterException; - -/** - * A transporter factory for repositories using the {@code http:} or {@code https:} protocol. The provided transporters - * support uploads to WebDAV servers and resumable downloads. - */ -@Named( "http" ) -public final class HttpTransporterFactory - implements TransporterFactory, Service -{ - - private Logger logger = NullLoggerFactory.LOGGER; - - private float priority = 5; - - /** - * Creates an (uninitialized) instance of this transporter factory. <em>Note:</em> In case of manual instantiation - * by clients, the new factory needs to be configured via its various mutators before first use or runtime errors - * will occur. - */ - public HttpTransporterFactory() - { - // enables default constructor - } - - @Inject - HttpTransporterFactory( LoggerFactory loggerFactory ) - { - setLoggerFactory( loggerFactory ); - } - - public void initService( ServiceLocator locator ) - { - setLoggerFactory( locator.getService( LoggerFactory.class ) ); - } - - /** - * Sets the logger factory to use for this component. - * - * @param loggerFactory The logger factory to use, may be {@code null} to disable logging. - * @return This component for chaining, never {@code null}. - */ - public HttpTransporterFactory setLoggerFactory( LoggerFactory loggerFactory ) - { - this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, HttpTransporter.class ); - return this; - } - - public float getPriority() - { - return priority; - } - - /** - * Sets the priority of this component. - * - * @param priority The priority. - * @return This component for chaining, never {@code null}. - */ - public HttpTransporterFactory setPriority( float priority ) - { - this.priority = priority; - return this; - } - - public Transporter newInstance( RepositorySystemSession session, RemoteRepository repository ) - throws NoTransporterException - { - return new HttpTransporter( repository, session, logger ); - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java deleted file mode 100644 index cbf2d93..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/LocalState.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.Closeable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScheme; -import org.apache.http.conn.ClientConnectionManager; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.transport.http.GlobalState.CompoundKey; - -/** - * Container for HTTP-related state that can be shared across invocations of the transporter to optimize the - * communication with server. - */ -final class LocalState - implements Closeable -{ - - private final GlobalState global; - - private final ClientConnectionManager connMgr; - - private final CompoundKey userTokenKey; - - private volatile Object userToken; - - private final CompoundKey expectContinueKey; - - private volatile Boolean expectContinue; - - private volatile Boolean webDav; - - private final ConcurrentMap<HttpHost, AuthSchemePool> authSchemePools; - - public LocalState( RepositorySystemSession session, RemoteRepository repo, SslConfig sslConfig ) - { - global = GlobalState.get( session ); - userToken = this; - if ( global == null ) - { - connMgr = GlobalState.newConnectionManager( sslConfig ); - userTokenKey = null; - expectContinueKey = null; - authSchemePools = new ConcurrentHashMap<HttpHost, AuthSchemePool>(); - } - else - { - connMgr = global.getConnectionManager( sslConfig ); - userTokenKey = new CompoundKey( repo.getId(), repo.getUrl(), repo.getAuthentication(), repo.getProxy() ); - expectContinueKey = new CompoundKey( repo.getUrl(), repo.getProxy() ); - authSchemePools = global.getAuthSchemePools(); - } - } - - public ClientConnectionManager getConnectionManager() - { - return connMgr; - } - - public Object getUserToken() - { - if ( userToken == this ) - { - userToken = ( global != null ) ? global.getUserToken( userTokenKey ) : null; - } - return userToken; - } - - public void setUserToken( Object userToken ) - { - this.userToken = userToken; - if ( global != null ) - { - global.setUserToken( userTokenKey, userToken ); - } - } - - public boolean isExpectContinue() - { - if ( expectContinue == null ) - { - expectContinue = - !Boolean.FALSE.equals( ( global != null ) ? global.getExpectContinue( expectContinueKey ) : null ); - } - return expectContinue; - } - - public void setExpectContinue( boolean enabled ) - { - expectContinue = enabled; - if ( global != null ) - { - global.setExpectContinue( expectContinueKey, enabled ); - } - } - - public Boolean getWebDav() - { - return webDav; - } - - public void setWebDav( boolean webDav ) - { - this.webDav = webDav; - } - - public AuthScheme getAuthScheme( HttpHost host ) - { - AuthSchemePool pool = authSchemePools.get( host ); - if ( pool != null ) - { - return pool.get(); - } - return null; - } - - public void setAuthScheme( HttpHost host, AuthScheme authScheme ) - { - AuthSchemePool pool = authSchemePools.get( host ); - if ( pool == null ) - { - AuthSchemePool p = new AuthSchemePool(); - pool = authSchemePools.putIfAbsent( host, p ); - if ( pool == null ) - { - pool = p; - } - } - pool.put( authScheme ); - } - - public void close() - { - if ( global == null ) - { - connMgr.shutdown(); - } - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java deleted file mode 100644 index 1264d04..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingAuthCache.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.HashMap; -import java.util.Map; - -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScheme; -import org.apache.http.client.AuthCache; - -/** - * Auth scheme cache that upon clearing releases all cached schemes into a pool for future reuse by other requests, - * thereby reducing challenge-response roundtrips. - */ -final class SharingAuthCache - implements AuthCache -{ - - private final LocalState state; - - private final Map<HttpHost, AuthScheme> authSchemes; - - public SharingAuthCache( LocalState state ) - { - this.state = state; - authSchemes = new HashMap<HttpHost, AuthScheme>(); - } - - private static HttpHost toKey( HttpHost host ) - { - if ( host.getPort() <= 0 ) - { - int port = host.getSchemeName().equalsIgnoreCase( "https" ) ? 443 : 80; - return new HttpHost( host.getHostName(), port, host.getSchemeName() ); - } - return host; - } - - public AuthScheme get( HttpHost host ) - { - host = toKey( host ); - AuthScheme authScheme = authSchemes.get( host ); - if ( authScheme == null ) - { - authScheme = state.getAuthScheme( host ); - authSchemes.put( host, authScheme ); - } - return authScheme; - } - - public void put( HttpHost host, AuthScheme authScheme ) - { - if ( authScheme != null ) - { - authSchemes.put( toKey( host ), authScheme ); - } - else - { - remove( host ); - } - } - - public void remove( HttpHost host ) - { - authSchemes.remove( toKey( host ) ); - } - - public void clear() - { - share(); - authSchemes.clear(); - } - - private void share() - { - for ( Map.Entry<HttpHost, AuthScheme> entry : authSchemes.entrySet() ) - { - state.setAuthScheme( entry.getKey(), entry.getValue() ); - } - } - - @Override - public String toString() - { - return authSchemes.toString(); - } - -} http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java ---------------------------------------------------------------------- diff --git a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java b/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java deleted file mode 100644 index 4464c26..0000000 --- a/aether-transport-http/src/main/java/org/eclipse/aether/transport/http/SharingHttpContext.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.eclipse.aether.transport.http; - -/* - * 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.Closeable; - -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.protocol.BasicHttpContext; - -/** - * HTTP context that shares certain attributes among requests to optimize the communication with the server. - * - * @see <a href="http://hc.apache.org/httpcomponents-client-ga/tutorial/html/advanced.html#stateful_conn">Stateful HTTP - * connections</a> - */ -final class SharingHttpContext - extends BasicHttpContext - implements Closeable -{ - - private final LocalState state; - - private final SharingAuthCache authCache; - - public SharingHttpContext( LocalState state ) - { - this.state = state; - authCache = new SharingAuthCache( state ); - super.setAttribute( ClientContext.AUTH_CACHE, authCache ); - } - - @Override - public Object getAttribute( String id ) - { - if ( ClientContext.USER_TOKEN.equals( id ) ) - { - return state.getUserToken(); - } - return super.getAttribute( id ); - } - - @Override - public void setAttribute( String id, Object obj ) - { - if ( ClientContext.USER_TOKEN.equals( id ) ) - { - state.setUserToken( obj ); - } - else - { - super.setAttribute( id, obj ); - } - } - - @Override - public Object removeAttribute( String id ) - { - if ( ClientContext.USER_TOKEN.equals( id ) ) - { - state.setUserToken( null ); - return null; - } - return super.removeAttribute( id ); - } - - public void close() - { - authCache.clear(); - } - -}