Migrated to the Apache HttpComponents library
This commit is contained in:
parent
8f55580ed2
commit
63f36b31cc
9 changed files with 111 additions and 76 deletions
5
pom.xml
5
pom.xml
|
@ -59,6 +59,11 @@
|
||||||
<artifactId>jdom2</artifactId>
|
<artifactId>jdom2</artifactId>
|
||||||
<version>2.0.6</version>
|
<version>2.0.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.4</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>info.picocli</groupId>
|
<groupId>info.picocli</groupId>
|
||||||
<artifactId>picocli</artifactId>
|
<artifactId>picocli</artifactId>
|
||||||
|
|
|
@ -32,6 +32,9 @@ To build, run "mvn clean package" in this folder.
|
||||||
|
|
||||||
|
|
||||||
This project depends on the following libraries.
|
This project depends on the following libraries.
|
||||||
|
- Apache HttpComponents
|
||||||
|
https://hc.apache.org/
|
||||||
|
(For JavaDocs, click HttpCore or HttpClient, then again under "Project reports".)
|
||||||
- Jackson JSON Processor 2.x
|
- Jackson JSON Processor 2.x
|
||||||
http://jackson.codehaus.org/Home
|
http://jackson.codehaus.org/Home
|
||||||
(For JavaDocs, look right.)
|
(For JavaDocs, look right.)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
"Disabled XML escaping when reencoding to ensure invalid chars cause an error",
|
"Disabled XML escaping when reencoding to ensure invalid chars cause an error",
|
||||||
"Changed logging framework to SLF4J/Logback",
|
"Changed logging framework to SLF4J/Logback",
|
||||||
"Changed command line parser to picocli",
|
"Changed command line parser to picocli",
|
||||||
|
"Migrated to the Apache HttpComponents library",
|
||||||
"Made launcher scripts on OSX find java the recommended way"
|
"Made launcher scripts on OSX find java the recommended way"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,7 @@ Changelog
|
||||||
- Added a Validate warning about FTL 1.5.13 for chars outside windows-1252
|
- Added a Validate warning about FTL 1.5.13 for chars outside windows-1252
|
||||||
- Changed logging framework to SLF4J/Logback
|
- Changed logging framework to SLF4J/Logback
|
||||||
- Changed command line parser to picocli
|
- Changed command line parser to picocli
|
||||||
|
- Migrated to the Apache HttpComponents library
|
||||||
- Made launcher scripts on OSX find java the recommended way
|
- Made launcher scripts on OSX find java the recommended way
|
||||||
|
|
||||||
1.9:
|
1.9:
|
||||||
|
|
|
@ -13,9 +13,9 @@ import net.vhati.modmanager.core.ComparableVersion;
|
||||||
*/
|
*/
|
||||||
public class AutoUpdateInfo {
|
public class AutoUpdateInfo {
|
||||||
private ComparableVersion latestVersion = null;
|
private ComparableVersion latestVersion = null;
|
||||||
private Map<String,String> latestURLs = new TreeMap<String,String>();
|
private Map<String, String> latestURLs = new TreeMap<String, String>();
|
||||||
private String notice = null;
|
private String notice = null;
|
||||||
private Map<ComparableVersion,List<String>> changelog = new TreeMap<ComparableVersion,List<String>>( Collections.reverseOrder() );
|
private Map<ComparableVersion, List<String>> changelog = new TreeMap<ComparableVersion, List<String>>( Collections.reverseOrder() );
|
||||||
|
|
||||||
|
|
||||||
public void setLatestVersion( ComparableVersion version ) {
|
public void setLatestVersion( ComparableVersion version ) {
|
||||||
|
@ -26,7 +26,6 @@ public class AutoUpdateInfo {
|
||||||
return latestVersion;
|
return latestVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setNotice( String s ) {
|
public void setNotice( String s ) {
|
||||||
notice = s;
|
notice = s;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +34,6 @@ public class AutoUpdateInfo {
|
||||||
return notice;
|
return notice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void putLatestURL( String os, String url ) {
|
public void putLatestURL( String os, String url ) {
|
||||||
latestURLs.put( os, url );
|
latestURLs.put( os, url );
|
||||||
}
|
}
|
||||||
|
@ -44,13 +42,11 @@ public class AutoUpdateInfo {
|
||||||
changelog.put( version, changeList );
|
changelog.put( version, changeList );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getLatestURLs() {
|
||||||
|
|
||||||
public Map<String,String> getLatestURLs() {
|
|
||||||
return latestURLs;
|
return latestURLs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<ComparableVersion,List<String>> getChangelog() {
|
public Map<ComparableVersion, List<String>> getChangelog() {
|
||||||
return changelog;
|
return changelog;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,9 @@ import java.util.regex.Pattern;
|
||||||
* It is composed of three parts:
|
* It is composed of three parts:
|
||||||
* - A series of period-separated positive ints.
|
* - A series of period-separated positive ints.
|
||||||
*
|
*
|
||||||
* - The numbers may be immediately followed by a short
|
* - The numbers may be immediately followed by a short suffix string.
|
||||||
* suffix string.
|
|
||||||
*
|
*
|
||||||
* - Finally, a string comment, separated from the rest
|
* - Finally, a string comment, separated from the rest by a space.
|
||||||
* by a space.
|
|
||||||
*
|
*
|
||||||
* The (numbers + suffix) or comment may appear alone.
|
* The (numbers + suffix) or comment may appear alone.
|
||||||
*
|
*
|
||||||
|
@ -38,7 +36,7 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
|
||||||
|
|
||||||
public ComparableVersion( int[] numbers, String suffix, String comment ) {
|
public ComparableVersion( int[] numbers, String suffix, String comment ) {
|
||||||
this.numbers = numbers;
|
this.numbers = numbers;
|
||||||
setSuffix( suffix );
|
setSuffix( suffix );
|
||||||
setComment( comment );
|
setComment( comment );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,16 +146,14 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
|
||||||
|
|
||||||
Matcher m = suffixPtn.matcher( s );
|
Matcher m = suffixPtn.matcher( s );
|
||||||
if ( m.matches() ) {
|
if ( m.matches() ) {
|
||||||
suffix = s;
|
|
||||||
|
|
||||||
// Matched groups 1 and 2... or 3.
|
// Matched groups 1 and 2... or 3.
|
||||||
|
|
||||||
if ( m.group(1) != null ) {
|
if ( m.group( 1 ) != null ) {
|
||||||
suffixDivider = m.group( 1 );
|
suffixDivider = m.group( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m.group(2) != null ) {
|
if ( m.group( 2 ) != null ) {
|
||||||
suffixNum = Integer.parseInt( m.group(2) );
|
suffixNum = Integer.parseInt( m.group( 2 ) );
|
||||||
} else {
|
} else {
|
||||||
suffixNum = -1;
|
suffixNum = -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package net.vhati.modmanager.json;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -28,10 +27,11 @@ public class JacksonAutoUpdateReader {
|
||||||
|
|
||||||
|
|
||||||
public static AutoUpdateInfo parse( File jsonFile ) {
|
public static AutoUpdateInfo parse( File jsonFile ) {
|
||||||
AutoUpdateInfo aui = new AutoUpdateInfo();
|
|
||||||
|
|
||||||
Exception exception = null;
|
Exception exception = null;
|
||||||
try {
|
try {
|
||||||
|
AutoUpdateInfo aui = new AutoUpdateInfo();
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
mapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true );
|
mapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true );
|
||||||
mapper.setVisibility( PropertyAccessor.FIELD, Visibility.ANY );
|
mapper.setVisibility( PropertyAccessor.FIELD, Visibility.ANY );
|
||||||
|
@ -43,9 +43,9 @@ public class JacksonAutoUpdateReader {
|
||||||
JsonNode latestNode = historyNode.get( "latest" );
|
JsonNode latestNode = historyNode.get( "latest" );
|
||||||
aui.setLatestVersion( new ComparableVersion( latestNode.get( "version" ).textValue() ) );
|
aui.setLatestVersion( new ComparableVersion( latestNode.get( "version" ).textValue() ) );
|
||||||
|
|
||||||
Iterator<Map.Entry<String,JsonNode>> fieldIt = latestNode.get( "urls" ).fields();
|
Iterator<Map.Entry<String, JsonNode>> fieldIt = latestNode.get( "urls" ).fields();
|
||||||
while ( fieldIt.hasNext() ) {
|
while ( fieldIt.hasNext() ) {
|
||||||
Map.Entry<String,JsonNode> entry = fieldIt.next();
|
Map.Entry<String, JsonNode> entry = fieldIt.next();
|
||||||
aui.putLatestURL( entry.getKey(), entry.getValue().textValue() );
|
aui.putLatestURL( entry.getKey(), entry.getValue().textValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,8 @@ public class JacksonAutoUpdateReader {
|
||||||
}
|
}
|
||||||
aui.putChanges( new ComparableVersion( releaseVersion ), changeList );
|
aui.putChanges( new ComparableVersion( releaseVersion ), changeList );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return aui;
|
||||||
}
|
}
|
||||||
catch ( JsonProcessingException e ) {
|
catch ( JsonProcessingException e ) {
|
||||||
exception = e;
|
exception = e;
|
||||||
|
@ -76,9 +78,8 @@ public class JacksonAutoUpdateReader {
|
||||||
}
|
}
|
||||||
if ( exception != null ) {
|
if ( exception != null ) {
|
||||||
log.error( "Failed to parse info about available updates", exception );
|
log.error( "Failed to parse info about available updates", exception );
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return aui;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,11 @@ public class JacksonCatalogReader {
|
||||||
|
|
||||||
|
|
||||||
public static ModDB parse( File jsonFile ) {
|
public static ModDB parse( File jsonFile ) {
|
||||||
ModDB modDB = new ModDB();
|
|
||||||
|
|
||||||
Exception exception = null;
|
Exception exception = null;
|
||||||
try {
|
try {
|
||||||
|
ModDB modDB = new ModDB();
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
mapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true );
|
mapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true );
|
||||||
mapper.setVisibility( PropertyAccessor.FIELD, Visibility.ANY );
|
mapper.setVisibility( PropertyAccessor.FIELD, Visibility.ANY );
|
||||||
|
@ -53,6 +54,8 @@ public class JacksonCatalogReader {
|
||||||
modDB.addMod( modInfo );
|
modDB.addMod( modInfo );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return modDB;
|
||||||
}
|
}
|
||||||
catch ( JsonProcessingException e ) {
|
catch ( JsonProcessingException e ) {
|
||||||
exception = e;
|
exception = e;
|
||||||
|
@ -65,6 +68,6 @@ public class JacksonCatalogReader {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return modDB;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,6 @@ import java.io.InputStreamReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -21,6 +17,14 @@ import java.util.Map;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
|
||||||
|
|
||||||
public class URLFetcher {
|
public class URLFetcher {
|
||||||
|
|
||||||
|
@ -28,104 +32,129 @@ public class URLFetcher {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads content from a url into a file, if the remote content has changed.
|
* Downloads content from a url to one file, and its ETag to another.
|
||||||
|
*
|
||||||
|
* If the ETag files exists, it will be read to inform the GET request.
|
||||||
|
*
|
||||||
|
* If the content has not changed, the destination file's modified date
|
||||||
|
* will be reset to the present time.
|
||||||
|
*
|
||||||
|
* If the content has changed, it will be written to the file, as will the
|
||||||
|
* new ETag.
|
||||||
*
|
*
|
||||||
* @return true if successfully downloaded, false otherwise
|
* @return true if successfully downloaded, false otherwise
|
||||||
*/
|
*/
|
||||||
public static boolean refetchURL( String url, File localFile, File eTagFile ) {
|
public static boolean refetchURL( String url, File localFile, File eTagFile ) {
|
||||||
String localETag = null;
|
String localETag = null;
|
||||||
|
|
||||||
log.debug( String.format( "Attempting to download the latest \"%s\".", localFile.getName() ) );
|
log.debug( String.format( "Attempting to download the latest \"%s\"", localFile.getName() ) );
|
||||||
if ( eTagFile.exists() ) {
|
if ( eTagFile.exists() ) {
|
||||||
// Load the old eTag.
|
// Load the old eTag.
|
||||||
InputStream etagIn = null;
|
InputStream etagIn = null;
|
||||||
|
BufferedReader etagReader = null;
|
||||||
try {
|
try {
|
||||||
etagIn = new FileInputStream( eTagFile );
|
etagIn = new FileInputStream( eTagFile );
|
||||||
BufferedReader br = new BufferedReader( new InputStreamReader( etagIn, "UTF-8" ) );
|
etagReader = new BufferedReader( new InputStreamReader( etagIn, "UTF-8" ) );
|
||||||
String line = br.readLine();
|
String line = etagReader.readLine();
|
||||||
if ( line.length() > 0 )
|
if ( line.length() > 0 ) {
|
||||||
localETag = line;
|
localETag = line;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
// Not serious enough to be a real error.
|
// Not serious enough to be a real error.
|
||||||
log.debug( String.format( "Error reading eTag from \"%s\".", eTagFile.getName() ), e );
|
log.debug( String.format( "Error reading eTag from \"%s\"", eTagFile.getName() ), e );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
try {if ( etagReader != null ) etagReader.close();}
|
||||||
|
catch ( IOException e ) {}
|
||||||
|
|
||||||
try {if ( etagIn != null ) etagIn.close();}
|
try {if ( etagIn != null ) etagIn.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String remoteETag = null;
|
HttpGet request = null;
|
||||||
InputStream urlIn = null;
|
|
||||||
OutputStream localOut = null;
|
OutputStream localOut = null;
|
||||||
|
String remoteETag = null;
|
||||||
|
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout( 5000 )
|
||||||
|
.setConnectTimeout( 5000 )
|
||||||
|
.setSocketTimeout( 10000 )
|
||||||
|
.setRedirectsEnabled( true )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CloseableHttpClient httpClient = HttpClientBuilder.create()
|
||||||
|
.setDefaultRequestConfig( requestConfig )
|
||||||
|
.disableAuthCaching()
|
||||||
|
.disableAutomaticRetries()
|
||||||
|
.disableConnectionState()
|
||||||
|
.disableCookieManagement()
|
||||||
|
//.setUserAgent( "" )
|
||||||
|
.build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
URLConnection conn = new URL( url ).openConnection();
|
request = new HttpGet( url );
|
||||||
|
|
||||||
if ( conn instanceof HttpURLConnection == false ) {
|
HttpResponse response = httpClient.execute( request );
|
||||||
log.error( String.format( "Non-Http(s) URL given for fetching: %s", url ) );
|
|
||||||
return false;
|
int status = response.getStatusLine().getStatusCode();
|
||||||
|
if ( status >= 200 && status < 300 ) {
|
||||||
|
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
if ( entity != null ) {
|
||||||
|
localOut = new FileOutputStream( localFile );
|
||||||
|
entity.writeTo( localOut );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( response.containsHeader( "ETag" ) ) {
|
||||||
|
remoteETag = response.getLastHeader( "ETag" ).getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
HttpURLConnection httpConn = (HttpURLConnection)conn;
|
else if ( status == 304 ) { // Not modified.
|
||||||
|
log.debug( String.format( "No need to download \"%s\", the server's copy has not been modified", localFile.getName() ) );
|
||||||
httpConn.setReadTimeout( 10000 );
|
|
||||||
if ( localETag != null )
|
|
||||||
httpConn.setRequestProperty( "If-None-Match", localETag );
|
|
||||||
httpConn.connect();
|
|
||||||
|
|
||||||
int responseCode = httpConn.getResponseCode();
|
|
||||||
|
|
||||||
if ( responseCode == HttpURLConnection.HTTP_NOT_MODIFIED ) {
|
|
||||||
log.debug( String.format( "No need to update \"%s\", the server's copy has not been modified since the previous check", localFile.getName() ) );
|
|
||||||
|
|
||||||
// Update the local file's timestamp as if it had downloaded.
|
// Update the local file's timestamp as if it had downloaded.
|
||||||
localFile.setLastModified( new Date().getTime() );
|
localFile.setLastModified( new Date().getTime() );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if ( responseCode == HttpURLConnection.HTTP_OK ) {
|
|
||||||
Map<String, List<String>> headerMap = httpConn.getHeaderFields();
|
|
||||||
List<String> eTagValues = headerMap.get( "ETag" );
|
|
||||||
if ( eTagValues != null && eTagValues.size() > 0 )
|
|
||||||
remoteETag = eTagValues.get( 0 );
|
|
||||||
|
|
||||||
urlIn = httpConn.getInputStream();
|
|
||||||
localOut = new FileOutputStream( localFile );
|
|
||||||
byte[] buf = new byte[4096];
|
|
||||||
int len;
|
|
||||||
while ( (len = urlIn.read(buf)) >= 0 ) {
|
|
||||||
localOut.write( buf, 0, len );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
log.error( String.format( "Download request failed for \"%s\": HTTP Code %d (%s)", httpConn.getURL(), responseCode, httpConn.getResponseMessage() ) );
|
throw new ClientProtocolException( "Unexpected response status: "+ status );
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch ( ClientProtocolException e ) {
|
||||||
|
log.error( "GET request failed for url: "+ request.getURI().toString(), e );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( String.format( "Error downloading the latest \"%s\"", localFile.getName() ), e );
|
log.error( "Download failed for url: "+ request.getURI().toString(), e );
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
try {if ( urlIn != null ) urlIn.close();}
|
try {if ( localOut != null ) localOut.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
|
|
||||||
try {if ( localOut != null ) localOut.close();}
|
try {httpClient.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( remoteETag != null ) {
|
if ( remoteETag != null ) {
|
||||||
// Save the new eTag.
|
// Save the new eTag.
|
||||||
OutputStream etagOut = null;
|
OutputStream etagOut = null;
|
||||||
|
BufferedWriter etagWriter = null;
|
||||||
try {
|
try {
|
||||||
etagOut = new FileOutputStream( eTagFile );
|
etagOut = new FileOutputStream( eTagFile );
|
||||||
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( etagOut, "UTF-8" ) );
|
etagWriter = new BufferedWriter( new OutputStreamWriter( etagOut, "UTF-8" ) );
|
||||||
bw.append( remoteETag );
|
etagWriter.append( remoteETag );
|
||||||
bw.flush();
|
etagWriter.flush();
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( String.format( "Error writing eTag to \"%s\"", eTagFile.getName() ), e );
|
log.error( String.format( "Error writing eTag to \"%s\"", eTagFile.getName() ), e );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
try {if ( etagWriter != null ) etagWriter.close();}
|
||||||
|
catch ( IOException e ) {}
|
||||||
|
|
||||||
try {if ( etagOut != null ) etagOut.close();}
|
try {if ( etagOut != null ) etagOut.close();}
|
||||||
catch ( IOException e ) {}
|
catch ( IOException e ) {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue