Browse Source

新增fastdfs支持

rogetfan 7 years ago
parent
commit
c7146be7b4
26 changed files with 7394 additions and 2 deletions
  1. 84 0
      src/main/java/io/renren/config/FastDFSConfig.java
  2. 472 0
      src/main/java/org/csource/common/Base64.java
  3. 190 0
      src/main/java/org/csource/common/IniFileReader.java
  4. 26 0
      src/main/java/org/csource/common/MyException.java
  5. 55 0
      src/main/java/org/csource/common/NameValuePair.java
  6. 201 0
      src/main/java/org/csource/fastdfs/ClientGlobal.java
  7. 26 0
      src/main/java/org/csource/fastdfs/DownloadCallback.java
  8. 49 0
      src/main/java/org/csource/fastdfs/DownloadStream.java
  9. 125 0
      src/main/java/org/csource/fastdfs/FileInfo.java
  10. 554 0
      src/main/java/org/csource/fastdfs/ProtoCommon.java
  11. 52 0
      src/main/java/org/csource/fastdfs/ProtoStructDecoder.java
  12. 66 0
      src/main/java/org/csource/fastdfs/ServerInfo.java
  13. 2076 0
      src/main/java/org/csource/fastdfs/StorageClient.java
  14. 799 0
      src/main/java/org/csource/fastdfs/StorageClient1.java
  15. 61 0
      src/main/java/org/csource/fastdfs/StorageServer.java
  16. 79 0
      src/main/java/org/csource/fastdfs/StructBase.java
  17. 226 0
      src/main/java/org/csource/fastdfs/StructGroupStat.java
  18. 934 0
      src/main/java/org/csource/fastdfs/StructStorageStat.java
  19. 990 0
      src/main/java/org/csource/fastdfs/TrackerClient.java
  20. 120 0
      src/main/java/org/csource/fastdfs/TrackerGroup.java
  21. 90 0
      src/main/java/org/csource/fastdfs/TrackerServer.java
  22. 27 0
      src/main/java/org/csource/fastdfs/UploadCallback.java
  23. 60 0
      src/main/java/org/csource/fastdfs/UploadStream.java
  24. 10 0
      src/main/resources/application-dev.yml
  25. 11 1
      src/main/resources/application-pro.yml
  26. 11 1
      src/main/resources/application-test.yml

+ 84 - 0
src/main/java/io/renren/config/FastDFSConfig.java

@ -0,0 +1,84 @@
1
package io.renren.config;
2
3
4
import org.csource.common.MyException;
5
import org.csource.fastdfs.ClientGlobal;
6
import org.csource.fastdfs.TrackerClient;
7
import org.csource.fastdfs.TrackerGroup;
8
import org.springframework.beans.factory.annotation.Value;
9
import org.springframework.cache.annotation.EnableCaching;
10
import org.springframework.context.annotation.Bean;
11
import org.springframework.context.annotation.Configuration;
12
13
import java.net.InetSocketAddress;
14
import java.util.List;
15
16
/**
17
 * Created by Glenn on 2017/5/18 0018.
18
 */
19
20
@Configuration("FastDFSConfig")
21
@EnableCaching//启用缓存的意思
22
public class FastDFSConfig {
23
    /***
24
     * Example
25
     @Autowired
26
     private TrackerClient client;
27
28
     上传至FastDFS
29
     StorageClient storageClient = new StorageClient(client.getConnection(), null);
30
     String[] ret = storageClient.upload_file(fileContent,type.getPureSuffix(), null);
31
     下载从FastDFS
32
33
     StorageClient storageClient = new StorageClient(client.getConnection(), null);
34
     FileInfo fi = storageClient.get_file_info(entity.getGroupName(), entity.getFileUri());
35
     if (fi == null) {
36
     throw new Exception("File information from FastDFS is null");
37
     }
38
     byte[] fileContent = storageClient.download_file(entity.getGroupName(), entity.getFileUri());
39
     if (fileContent == null) {
40
     throw new Exception("File entity from FastDFS is null");
41
     }
42
     * */
43
44
45
    @Value("${fdfs.networkTimeout:#{null}}")
46
    private Integer networkTimeout;
47
    @Value("${fdfs.connectTimeout:#{null}}")
48
    private Integer connectTimeout;
49
    @Value("${fdfs.trackerServer:#{null}}")
50
    List<String> trackerServer;
51
    @Value("${fdfs.charset:#{null}}")
52
    private String charset;
53
    @Value("${fdfs.trackerHttpPort:#{null}}")
54
    private Integer trackerHttpPort;
55
    @Value("${fdfs.antiStealToken:#{null}}")
56
    private Boolean antiStealToken;
57
    @Value("${fdfs.secretKey:#{null}}")
58
    private String secretKey;
59
60
    @Bean
61
    public TrackerClient getTrackerClient() throws MyException {
62
        String[] parts;
63
        ClientGlobal.setG_anti_steal_token(antiStealToken);
64
        ClientGlobal.setG_charset(charset);
65
        ClientGlobal.setG_connect_timeout(connectTimeout*1000);
66
        ClientGlobal.setG_network_timeout(networkTimeout*1000);
67
        ClientGlobal.setG_secret_key(secretKey);
68
        InetSocketAddress[] tracker_servers = new InetSocketAddress[trackerServer.size()];
69
        for (int i=0; i<trackerServer.size(); i++)
70
        {
71
            parts =trackerServer.get(i).split("\\:", 2);
72
            if (parts.length != 2)
73
            {
74
                throw new MyException("the value of item \"tracker_server\" is invalid, the correct format is host:port");
75
            }
76
77
            tracker_servers[i] = new InetSocketAddress(parts[0].trim(), Integer.parseInt(parts[1].trim()));
78
        }
79
        ClientGlobal.setG_tracker_group(new TrackerGroup(tracker_servers));
80
        ClientGlobal.setG_tracker_http_port(trackerHttpPort);
81
        TrackerClient trackerClient = new TrackerClient();
82
        return trackerClient;
83
    }
84
}

+ 472 - 0
src/main/java/org/csource/common/Base64.java

@ -0,0 +1,472 @@
1
package org.csource.common;
2
3
import java.io.IOException;
4
5
/**
6
 * Freeware from:
7
 * Roedy Green
8
 * Canadian Mind Products
9
 * #327 - 964 Heywood Avenue
10
 * Victoria, BC Canada V8V 2Y5
11
 * tel:(250) 361-9093
12
 * mailto:roedy@mindprod.com
13
 */
14
15
/**
16
 * Encode arbitrary binary into printable ASCII using BASE64 encoding.
17
 * very loosely based on the Base64 Reader by
18
 * Dr. Mark Thornton
19
 * Optrak Distribution Software Ltd.
20
 * http://www.optrak.co.uk
21
 * and Kevin Kelley's  http://www.ruralnet.net/~kelley/java/Base64.java
22
 *
23
 * Base64 is a way of encoding 8-bit characters using only ASCII printable
24
 * characters similar to UUENCODE.  UUENCODE includes a filename where BASE64 does not.
25
 * The spec is described in RFC 2045.  Base64 is a scheme where
26
 * 3 bytes are concatenated, then split to form 4 groups of 6-bits each; and
27
 * each 6-bits gets translated to an encoded printable ASCII character, via a
28
 * table lookup.  An encoded string is therefore longer than the original by
29
 * about 1/3.  The "=" character is used to pad the end.  Base64 is used,
30
 * among other things, to encode the user:password string in an
31
 * Authorization: header for HTTP.  Don't confuse Base64 with
32
 * x-www-form-urlencoded which is handled by
33
 * Java.net.URLEncoder.encode/decode
34
 * If you don't like this code, there is another implementation at http://www.ruffboy.com/download.htm
35
 * Sun has an undocumented method called sun.misc.Base64Encoder.encode.
36
 * You could use hex, simpler to code, but not as compact.
37
 *
38
 * If you wanted to encode a giant file, you could do it in large chunks that
39
 * are even multiples of 3 bytes, except for the last chunk, and append the outputs.
40
 *
41
 * To encode a string, rather than binary data java.net.URLEncoder may be better. See
42
 * printable characters in the Java glossary for a discussion of the differences.
43
 *
44
 * version 1.4 2002 February 15  -- correct bugs with uneven line lengths,
45
 *                                  allow you to configure line separator.
46
 *                                  now need Base64 object and instance methods.
47
 *                                  new mailing address.
48
 * version 1.3 2000 September 12 -- fix problems with estimating output length in encode
49
 * version 1.2 2000 September 09 -- now handles decode as well.
50
 * version 1.1 1999 December 04 -- more symmetrical encoding algorithm.
51
 *                                 more accurate StringBuffer allocation size.
52
 * version 1.0 1999 December 03 -- posted in comp.lang.java.programmer.
53
 * Futures Streams or files.
54
 */
55
56
public class Base64
57
{
58
59
   /**
60
    * how we separate lines, e.g. \n, \r\n, \r etc.
61
    */
62
   private String lineSeparator = System.getProperty( "line.separator" );
63
64
   /**
65
    * max chars per line, excluding lineSeparator.  A multiple of 4.
66
    */
67
   private int lineLength = 72;
68
69
   private char[] valueToChar = new char[64];
70
71
   /**
72
    * binary value encoded by a given letter of the alphabet 0..63
73
    */
74
   private int[] charToValue = new int[256];
75
   
76
   private int[] charToPad = new int[4];
77
   
78
   /* constructor */
79
   public Base64()
80
   {
81
   	  this.init('+', '/', '=');
82
   }
83
   
84
   /* constructor */
85
   public Base64(char chPlus, char chSplash, char chPad, int lineLength)
86
   {
87
   	  this.init(chPlus, chSplash, chPad);
88
   	  this.lineLength = lineLength;
89
   }
90
91
   public Base64(int lineLength)
92
   {
93
       this.lineLength = lineLength;
94
   }
95
96
   /* initialise defaultValueToChar and defaultCharToValue tables */
97
   private void init(char chPlus, char chSplash, char chPad)
98
   {
99
   		int index = 0;
100
      // build translate this.valueToChar table only once.
101
      // 0..25 -> 'A'..'Z'
102
      for ( int i='A'; i<='Z'; i++) {
103
         this.valueToChar[index++] = (char)i;
104
      }
105
      
106
      // 26..51 -> 'a'..'z'
107
      for ( int i='a'; i<='z'; i++ ) {
108
         this.valueToChar[index++] = (char)i;
109
      }
110
      
111
      // 52..61 -> '0'..'9'
112
      for ( int i='0'; i<='9'; i++) {
113
         this.valueToChar[index++] = (char)i;
114
      }
115
      
116
      this.valueToChar[index++] = chPlus;
117
      this.valueToChar[index++] = chSplash;
118
119
      // build translate defaultCharToValue table only once.
120
      for ( int i=0; i<256; i++ )
121
      {
122
         this.charToValue[i] = IGNORE;  // default is to ignore
123
      }
124
125
      for ( int i=0; i<64; i++ )
126
      {
127
         this.charToValue[this.valueToChar[i]] = i;
128
      }
129
130
      this.charToValue[chPad] = PAD;
131
      java.util.Arrays.fill(this.charToPad, chPad);
132
   }
133
   
134
   /**
135
    * Encode an arbitrary array of bytes as Base64 printable ASCII.
136
    * It will be broken into lines of 72 chars each.  The last line is not
137
    * terminated with a line separator.
138
    * The output will always have an even multiple of data characters,
139
    * exclusive of \n.  It is padded out with =.
140
    */
141
   public String encode(byte[] b) throws IOException
142
      {
143
      // Each group or partial group of 3 bytes becomes four chars
144
      // covered quotient
145
      int outputLength = ((b.length + 2) / 3) * 4;
146
147
      // account for trailing newlines, on all but the very last line
148
      if ( lineLength != 0 )
149
         {
150
          int lines =  ( outputLength + lineLength -1 ) / lineLength - 1;
151
          if ( lines > 0 )
152
            {
153
             outputLength += lines  * lineSeparator.length();
154
            }
155
         }
156
157
      // must be local for recursion to work.
158
      StringBuffer sb = new StringBuffer( outputLength );
159
160
      // must be local for recursion to work.
161
      int linePos = 0;
162
163
      // first deal with even multiples of 3 bytes.
164
      int len = (b.length / 3) * 3;
165
      int leftover = b.length - len;
166
      for ( int i=0; i<len; i+=3 )
167
         {
168
         // Start a new line if next 4 chars won't fit on the current line
169
         // We can't encapsulete the following code since the variable need to
170
         // be local to this incarnation of encode.
171
         linePos += 4;
172
         if ( linePos > lineLength )
173
            {
174
            if ( lineLength != 0 )
175
               {
176
               sb.append(lineSeparator);
177
               }
178
            linePos = 4;
179
            }
180
181
         // get next three bytes in unsigned form lined up,
182
         // in big-endian order
183
         int combined = b[i+0] & 0xff;
184
         combined <<= 8;
185
         combined |= b[i+1] & 0xff;
186
         combined <<= 8;
187
         combined |= b[i+2] & 0xff;
188
189
         // break those 24 bits into a 4 groups of 6 bits,
190
         // working LSB to MSB.
191
         int c3 = combined & 0x3f;
192
         combined >>>= 6;
193
         int c2 = combined & 0x3f;
194
         combined >>>= 6;
195
         int c1 = combined & 0x3f;
196
         combined >>>= 6;
197
         int c0 = combined & 0x3f;
198
199
         // Translate into the equivalent alpha character
200
         // emitting them in big-endian order.
201
         sb.append( valueToChar[c0]);
202
         sb.append( valueToChar[c1]);
203
         sb.append( valueToChar[c2]);
204
         sb.append( valueToChar[c3]);
205
         }
206
207
      // deal with leftover bytes
208
      switch ( leftover )
209
         {
210
         case 0:
211
         default:
212
            // nothing to do
213
            break;
214
215
         case 1:
216
            // One leftover byte generates xx==
217
            // Start a new line if next 4 chars won't fit on the current line
218
            linePos += 4;
219
            if ( linePos > lineLength )
220
               {
221
222
               if ( lineLength != 0 )
223
                  {
224
                  sb.append(lineSeparator);
225
                  }
226
               linePos = 4;
227
               }
228
229
            // Handle this recursively with a faked complete triple.
230
            // Throw away last two chars and replace with ==
231
            sb.append(encode(new byte[] {b[len], 0, 0}
232
                            ).substring(0,2));
233
            sb.append("==");
234
            break;
235
236
         case 2:
237
            // Two leftover bytes generates xxx=
238
            // Start a new line if next 4 chars won't fit on the current line
239
            linePos += 4;
240
            if ( linePos > lineLength )
241
               {
242
               if ( lineLength != 0 )
243
                  {
244
                  sb.append(lineSeparator);
245
                  }
246
               linePos = 4;
247
               }
248
            // Handle this recursively with a faked complete triple.
249
            // Throw away last char and replace with =
250
            sb.append(encode(new byte[] {b[len], b[len+1], 0}
251
                            ).substring(0,3));
252
            sb.append("=");
253
            break;
254
255
         } // end switch;
256
257
      if ( outputLength != sb.length() )
258
         {
259
         System.out.println("oops: minor program flaw: output length mis-estimated");
260
         System.out.println("estimate:" + outputLength);
261
         System.out.println("actual:" + sb.length());
262
         }
263
      return sb.toString();
264
      }// end encode
265
266
   /**
267
    * decode a well-formed complete Base64 string back into an array of bytes.
268
    * It must have an even multiple of 4 data characters (not counting \n),
269
    * padded out with = as needed.
270
    */
271
   public byte[] decodeAuto( String s) {   	 
272
   	 int nRemain = s.length() % 4;
273
   	 if (nRemain == 0) {
274
   	 	 return this.decode(s);
275
   	 } else {
276
   	   return this.decode(s + new String(this.charToPad, 0, 4 - nRemain));
277
   	 }
278
   }
279
   
280
   /**
281
    * decode a well-formed complete Base64 string back into an array of bytes.
282
    * It must have an even multiple of 4 data characters (not counting \n),
283
    * padded out with = as needed.
284
    */
285
   public byte[] decode( String s)
286
      {
287
288
      // estimate worst case size of output array, no embedded newlines.
289
      byte[] b = new byte[(s.length() / 4) * 3];
290
291
      // tracks where we are in a cycle of 4 input chars.
292
      int cycle = 0;
293
294
      // where we combine 4 groups of 6 bits and take apart as 3 groups of 8.
295
      int combined = 0;
296
297
      // how many bytes we have prepared.
298
      int j = 0;
299
      // will be an even multiple of 4 chars, plus some embedded \n
300
      int len = s.length();
301
      int dummies = 0;
302
      for ( int i=0; i<len; i++ )
303
         {
304
305
         int c = s.charAt(i);
306
         int value  = (c <= 255) ? charToValue[c] : IGNORE;
307
         // there are two magic values PAD (=) and IGNORE.
308
         switch ( value )
309
            {
310
            case IGNORE:
311
               // e.g. \n, just ignore it.
312
               break;
313
314
            case PAD:
315
               value = 0;
316
               dummies++;
317
               // fallthrough
318
            default:
319
               /* regular value character */
320
               switch ( cycle )
321
                  {
322
                  case 0:
323
                     combined = value;
324
                     cycle = 1;
325
                     break;
326
327
                  case 1:
328
                     combined <<= 6;
329
                     combined |= value;
330
                     cycle = 2;
331
                     break;
332
333
                  case 2:
334
                     combined <<= 6;
335
                     combined |= value;
336
                     cycle = 3;
337
                     break;
338
339
                  case 3:
340
                     combined <<= 6;
341
                     combined |= value;
342
                     // we have just completed a cycle of 4 chars.
343
                     // the four 6-bit values are in combined in big-endian order
344
                     // peel them off 8 bits at a time working lsb to msb
345
                     // to get our original 3 8-bit bytes back
346
347
                     b[j+2] = (byte)combined;
348
                     combined >>>= 8;
349
                     b[j+1] = (byte)combined;
350
                     combined >>>= 8;
351
                     b[j] = (byte)combined;
352
                     j += 3;
353
                     cycle = 0;
354
                     break;
355
                  }
356
               break;
357
            }
358
         } // end for
359
      if ( cycle != 0 )
360
         {
361
         throw new ArrayIndexOutOfBoundsException ("Input to decode not an even multiple of 4 characters; pad with =.");
362
         }
363
      j -= dummies;
364
      if ( b.length != j )
365
         {
366
         byte[] b2 = new byte[j];
367
         System.arraycopy(b, 0, b2, 0, j);
368
         b = b2;
369
         }
370
      return b;
371
372
      }// end decode
373
374
   /**
375
    * determines how long the lines are that are generated by encode.
376
    * Ignored by decode.
377
    * @param length 0 means no newlines inserted. Must be a multiple of 4.
378
    */
379
   public void setLineLength(int length)
380
      {
381
      this.lineLength = (length/4) * 4;
382
      }
383
384
   /**
385
    * How lines are separated.
386
    * Ignored by decode.
387
    * @param lineSeparator may be "" but not null.
388
    * Usually contains only a combination of chars \n and \r.
389
    * Could be any chars not in set A-Z a-z 0-9 + /.
390
    */
391
   public  void setLineSeparator(String lineSeparator)
392
      {
393
      this.lineSeparator = lineSeparator;
394
      }
395
396
   /**
397
    * Marker value for chars we just ignore, e.g. \n \r high ascii
398
    */
399
   static final int IGNORE = -1;
400
401
   /**
402
    * Marker for = trailing pad
403
    */
404
   static final int PAD = -2;
405
406
   /**
407
    * used to disable test driver
408
    */
409
   private static final boolean debug = true;
410
411
   /**
412
    * debug display array
413
    */
414
   public static void show (byte[] b)
415
   {
416
      int count = 0;
417
      int rows = 0;
418
419
420
      for ( int i=0; i<b.length; i++ )
421
      {
422
         if(count == 8)
423
         {
424
            System.out.print("  ");
425
         }
426
         else if(count == 16)
427
         {
428
            System.out.println("");
429
            count = 0;
430
            continue;
431
         }
432
         System.out.print( Integer.toHexString(b[i] & 0xFF).toUpperCase() + " ");
433
         count ++;
434
435
      }
436
      System.out.println();
437
   }
438
439
   /**
440
    * debug display array
441
    */
442
   public static void display (byte[] b)
443
      {
444
      for ( int i=0; i<b.length; i++ )
445
         {
446
         System.out.print( (char)b[i]);
447
         }
448
      System.out.println();
449
      }
450
451
   public static void test()
452
   {
453
       try
454
       {
455
          Base64 b64 = new Base64();
456
457
          //encode
458
          //str64 = b64.encode(str.getBytes());
459
          //System.out.println(str64);
460
461
          String str64 = "CwUEFYoAAAADjQMC7ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267EI=";
462
          //decode
463
          byte[] theBytes = b64.decode(str64);
464
          show(theBytes);
465
       }
466
       catch(Exception e)
467
       {
468
          e.printStackTrace();
469
       }
470
   }
471
} // end Base64
472

+ 190 - 0
src/main/java/org/csource/common/IniFileReader.java

@ -0,0 +1,190 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
**/
8
9
package org.csource.common;
10
11
import java.io.BufferedReader;
12
import java.io.FileNotFoundException;
13
import java.io.FileReader;
14
import java.io.IOException;
15
import java.util.ArrayList;
16
import java.util.Hashtable;
17
18
/**
19
* ini file reader / parser
20
* @author Happy Fish / YuQing
21
* @version Version 1.0
22
*/
23
public class IniFileReader
24
{
25
	private Hashtable paramTable;
26
	private String conf_filename;
27
	
28
/**
29
* @param conf_filename config filename
30
*/
31
	public IniFileReader(String conf_filename) throws FileNotFoundException, IOException
32
	{
33
		this.conf_filename = conf_filename;
34
		loadFromFile(conf_filename);
35
	}
36
	
37
/**
38
* get the config filename
39
* @return config filename
40
*/
41
	public String getConfFilename()
42
	{
43
		return this.conf_filename;
44
	}
45
	
46
/**
47
* get string value from config file
48
* @param name item name in config file
49
* @return string value
50
*/
51
	public String getStrValue(String name)
52
	{
53
		Object obj;
54
		obj = this.paramTable.get(name);
55
		if (obj == null)
56
		{
57
			return null;
58
		}
59
		
60
		if (obj instanceof String)
61
		{
62
			return (String)obj;
63
		}
64
		
65
		return (String)((ArrayList)obj).get(0);
66
	}
67
68
/**
69
* get int value from config file
70
* @param name item name in config file
71
* @param default_value the default value
72
* @return int value
73
*/
74
	public int getIntValue(String name, int default_value)
75
	{
76
		String szValue = this.getStrValue(name);
77
		if (szValue == null)
78
		{
79
			return default_value;
80
		}
81
		
82
		return Integer.parseInt(szValue);
83
	}
84
85
/**
86
* get boolean value from config file
87
* @param name item name in config file
88
* @param default_value the default value
89
* @return boolean value
90
*/
91
	public boolean getBoolValue(String name, boolean default_value)
92
	{
93
		String szValue = this.getStrValue(name);
94
		if (szValue == null)
95
		{
96
			return default_value;
97
		}
98
		
99
		return szValue.equalsIgnoreCase("yes") || szValue.equalsIgnoreCase("on") || 
100
					 szValue.equalsIgnoreCase("true") || szValue.equals("1");
101
	}
102
	
103
/**
104
* get all values from config file
105
* @param name item name in config file
106
* @return string values (array)
107
*/
108
	public String[] getValues(String name)
109
	{
110
		Object obj;
111
		String[] values;
112
		
113
		obj = this.paramTable.get(name);
114
		if (obj == null)
115
		{
116
			return null;
117
		}
118
		
119
		if (obj instanceof String)
120
		{
121
			values = new String[1];
122
			values[0] = (String)obj;
123
			return values;
124
		}
125
		
126
		Object[] objs = ((ArrayList)obj).toArray();
127
		values = new String[objs.length];
128
		System.arraycopy(objs, 0, values, 0, objs.length);
129
		return values;
130
	}
131
	
132
	private void loadFromFile(String conf_filename) throws FileNotFoundException, IOException
133
	{
134
		FileReader fReader;
135
		BufferedReader buffReader;
136
		String line;
137
		String[] parts;
138
		String name;
139
		String value;
140
		Object obj;
141
		ArrayList valueList;
142
		
143
	  fReader = new FileReader(conf_filename);
144
	  buffReader = new BufferedReader(fReader);
145
	  this.paramTable = new Hashtable();
146
	  
147
	  try
148
	  {
149
	  	while ((line=buffReader.readLine()) != null)
150
	  	{
151
	  		line = line.trim();
152
	  		if (line.length() == 0 || line.charAt(0) == '#')
153
	  		{
154
	  			continue;
155
	  		}
156
	  		
157
	  		parts = line.split("=", 2);
158
	  		if (parts.length != 2)
159
	  		{
160
	  			continue;
161
	  		}
162
	  	
163
	  		name = parts[0].trim();
164
	  		value = parts[1].trim();
165
	  		
166
	  		obj = this.paramTable.get(name);
167
	  		if (obj == null)
168
	  		{
169
	  			this.paramTable.put(name, value);
170
	  		}
171
	  		else if (obj instanceof String)
172
	  		{
173
	  			valueList = new ArrayList();
174
	  			valueList.add(obj);
175
	  			valueList.add(value);
176
	  			this.paramTable.put(name, valueList);
177
	  		}
178
	  		else
179
	  		{
180
	  			valueList = (ArrayList)obj;
181
	  			valueList.add(value);
182
	  		}
183
	  	}
184
	  }
185
	  finally
186
	  {
187
	  	fReader.close();
188
	  }
189
  }  
190
}

+ 26 - 0
src/main/java/org/csource/common/MyException.java

@ -0,0 +1,26 @@
1
/*
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.common;
10
11
/**
12
* My Exception
13
* @author Happy Fish / YuQing
14
* @version Version 1.0
15
*/
16
public class MyException extends Exception
17
{
18
    public MyException()
19
    {
20
    }
21
    
22
    public MyException(String message)
23
    {
24
    		super(message);
25
    }
26
}

+ 55 - 0
src/main/java/org/csource/common/NameValuePair.java

@ -0,0 +1,55 @@
1
/*
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.common;
10
11
/**
12
* name(key) and value pair model
13
* @author Happy Fish / YuQing
14
* @version Version 1.0
15
*/
16
public class NameValuePair
17
{
18
    protected String name;
19
    protected String value;
20
21
    public NameValuePair()
22
    {
23
    }
24
25
    public NameValuePair(String name)
26
    {
27
        this.name = name;
28
    }
29
30
    public NameValuePair(String name, String value)
31
    {
32
        this.name = name;
33
        this.value = value;
34
    }
35
36
    public String getName()
37
    {
38
        return this.name;
39
    }
40
41
    public String getValue()
42
    {
43
        return this.value;
44
    }
45
46
    public void setName(String name)
47
    {
48
        this.name = name;
49
    }
50
51
    public void setValue(String value)
52
    {
53
        this.value = value;
54
    }
55
}

+ 201 - 0
src/main/java/org/csource/fastdfs/ClientGlobal.java

@ -0,0 +1,201 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
**/
8
9
package org.csource.fastdfs;
10
11
import org.csource.common.IniFileReader;
12
import org.csource.common.MyException;
13
14
import java.io.FileNotFoundException;
15
import java.io.IOException;
16
import java.net.InetSocketAddress;
17
import java.net.Socket;
18
19
/**
20
* Global variables
21
* @author Happy Fish / YuQing
22
* @version Version 1.11
23
*/
24
public class ClientGlobal
25
{
26
	public static int g_connect_timeout; //millisecond
27
	public static int g_network_timeout; //millisecond
28
	public static String g_charset;
29
	public static int g_tracker_http_port;
30
	public static boolean g_anti_steal_token;  //if anti-steal token
31
	public static String g_secret_key;   //generage token secret key
32
	public static TrackerGroup g_tracker_group;
33
	
34
	public static final int DEFAULT_CONNECT_TIMEOUT = 5;  //second
35
	public static final int DEFAULT_NETWORK_TIMEOUT = 30; //second
36
	
37
	private ClientGlobal()
38
	{
39
	}
40
	
41
/**
42
* load global variables
43
* @param conf_filename config filename
44
*/
45
	public static void init(String conf_filename) throws FileNotFoundException, IOException, MyException
46
	{
47
  		IniFileReader iniReader;
48
  		String[] szTrackerServers;
49
			String[] parts;
50
			
51
  		iniReader = new IniFileReader(conf_filename);
52
53
			g_connect_timeout = iniReader.getIntValue("connect_timeout", DEFAULT_CONNECT_TIMEOUT);
54
  		if (g_connect_timeout < 0)
55
  		{
56
  			g_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
57
  		}
58
  		g_connect_timeout *= 1000; //millisecond
59
  		
60
  		g_network_timeout = iniReader.getIntValue("network_timeout", DEFAULT_NETWORK_TIMEOUT);
61
  		if (g_network_timeout < 0)
62
  		{
63
  			g_network_timeout = DEFAULT_NETWORK_TIMEOUT;
64
  		}
65
  		g_network_timeout *= 1000; //millisecond
66
67
  		g_charset = iniReader.getStrValue("charset");
68
  		if (g_charset == null || g_charset.length() == 0)
69
  		{
70
  			g_charset = "ISO8859-1";
71
  		}
72
  		
73
  		szTrackerServers = iniReader.getValues("tracker_server");
74
  		if (szTrackerServers == null)
75
  		{
76
  			throw new MyException("item \"tracker_server\" in " + conf_filename + " not found");
77
  		}
78
  		
79
  		InetSocketAddress[] tracker_servers = new InetSocketAddress[szTrackerServers.length];
80
  		for (int i=0; i<szTrackerServers.length; i++)
81
  		{
82
  			parts = szTrackerServers[i].split("\\:", 2);
83
  			if (parts.length != 2)
84
  			{
85
  				throw new MyException("the value of item \"tracker_server\" is invalid, the correct format is host:port");
86
  			}
87
  			
88
  			tracker_servers[i] = new InetSocketAddress(parts[0].trim(), Integer.parseInt(parts[1].trim()));
89
  		}
90
  		g_tracker_group = new TrackerGroup(tracker_servers);
91
  		
92
  		g_tracker_http_port = iniReader.getIntValue("http.tracker_http_port", 80);
93
  		g_anti_steal_token = iniReader.getBoolValue("http.anti_steal_token", false);
94
  		if (g_anti_steal_token)
95
  		{
96
  			g_secret_key = iniReader.getStrValue("http.secret_key");
97
  		}
98
	}
99
	
100
/**
101
* construct Socket object
102
* @param ip_addr ip address or hostname
103
* @param port port number
104
* @return connected Socket object
105
*/
106
	public static Socket getSocket(String ip_addr, int port) throws IOException
107
	{
108
		Socket sock = new Socket();
109
		sock.setSoTimeout(ClientGlobal.g_network_timeout);
110
		sock.connect(new InetSocketAddress(ip_addr, port), ClientGlobal.g_connect_timeout);
111
		return sock;
112
	}
113
	
114
/**
115
* construct Socket object
116
* @param addr InetSocketAddress object, including ip address and port
117
* @return connected Socket object
118
*/
119
	public static Socket getSocket(InetSocketAddress addr) throws IOException
120
	{
121
		Socket sock = new Socket();
122
		sock.setSoTimeout(ClientGlobal.g_network_timeout);
123
		sock.connect(addr, ClientGlobal.g_connect_timeout);
124
		return sock;
125
	}
126
	
127
	public static int getG_connect_timeout()
128
	{
129
		return g_connect_timeout;
130
	}
131
	
132
	public static void setG_connect_timeout(int connect_timeout)
133
	{
134
		ClientGlobal.g_connect_timeout = connect_timeout;
135
	}
136
	
137
	public static int getG_network_timeout()
138
	{
139
		return g_network_timeout;
140
	}
141
	
142
	public static void setG_network_timeout(int network_timeout)
143
	{
144
		ClientGlobal.g_network_timeout = network_timeout;
145
	}
146
	
147
	public static String getG_charset()
148
	{
149
		return g_charset;
150
	}
151
	
152
	public static void setG_charset(String charset)
153
	{
154
		ClientGlobal.g_charset = charset;
155
	}
156
	
157
	public static int getG_tracker_http_port()
158
	{
159
		return g_tracker_http_port;
160
	}
161
	
162
	public static void setG_tracker_http_port(int tracker_http_port)
163
	{
164
		ClientGlobal.g_tracker_http_port = tracker_http_port;
165
	}
166
	
167
	public static boolean getG_anti_steal_token()
168
	{
169
		return g_anti_steal_token;
170
	}
171
	
172
	public static boolean isG_anti_steal_token()
173
	{
174
		return g_anti_steal_token;
175
	}
176
	
177
	public static void setG_anti_steal_token(boolean anti_steal_token)
178
	{
179
		ClientGlobal.g_anti_steal_token = anti_steal_token;
180
	}
181
	
182
	public static String getG_secret_key()
183
	{
184
		return g_secret_key;
185
	}
186
	
187
	public static void setG_secret_key(String secret_key)
188
	{
189
		ClientGlobal.g_secret_key = secret_key;
190
	}
191
	
192
	public static TrackerGroup getG_tracker_group()
193
	{
194
		return g_tracker_group;
195
	}
196
	
197
	public static void setG_tracker_group(TrackerGroup tracker_group)
198
	{
199
		ClientGlobal.g_tracker_group = tracker_group;
200
	}
201
}

+ 26 - 0
src/main/java/org/csource/fastdfs/DownloadCallback.java

@ -0,0 +1,26 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
/**
12
* Download file callback interface
13
* @author Happy Fish / YuQing
14
* @version Version 1.4
15
*/
16
public interface DownloadCallback
17
{
18
	/**
19
	* recv file content callback function, may be called more than once when the file downloaded
20
	* @param file_size file size
21
	*	@param data data buff
22
	* @param bytes data bytes
23
	* @return 0 success, return none zero(errno) if fail
24
	*/
25
	public int recv(long file_size, byte[] data, int bytes);
26
}

+ 49 - 0
src/main/java/org/csource/fastdfs/DownloadStream.java

@ -0,0 +1,49 @@
1
package org.csource.fastdfs;
2
3
import java.io.IOException;
4
import java.io.OutputStream;
5
6
/**
7
* Download file by stream (download callback class)
8
* @author  zhouzezhong & Happy Fish / YuQing
9
* @version Version 1.11
10
*/
11
public class DownloadStream implements DownloadCallback
12
{
13
	private OutputStream out;
14
	private long currentBytes = 0;
15
	
16
	public DownloadStream(OutputStream out)
17
	{
18
		super();
19
		this.out = out;
20
	}
21
22
	/**
23
	* recv file content callback function, may be called more than once when the file downloaded
24
	* @param fileSize file size
25
	*	@param data data buff
26
	* @param bytes data bytes
27
	* @return 0 success, return none zero(errno) if fail
28
	*/
29
	public int recv(long fileSize, byte[] data, int bytes)
30
	{
31
		try
32
		{
33
			out.write(data, 0, bytes);
34
		}
35
		catch(IOException ex)
36
		{
37
			ex.printStackTrace(); 
38
			return -1;
39
		}
40
		
41
		currentBytes +=	bytes;
42
		if (this.currentBytes == fileSize)
43
		{
44
			this.currentBytes = 0;
45
		}
46
		
47
		return 0;
48
	}
49
}

+ 125 - 0
src/main/java/org/csource/fastdfs/FileInfo.java

@ -0,0 +1,125 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.text.SimpleDateFormat;
12
import java.util.Date;
13
14
/**
15
* Server Info
16
* @author Happy Fish / YuQing
17
* @version Version 1.23
18
*/
19
public class FileInfo
20
{
21
	protected String source_ip_addr;
22
	protected long file_size;
23
	protected Date create_timestamp;
24
	protected int crc32;
25
26
/**
27
* Constructor
28
* @param file_size the file size
29
* @param create_timestamp create timestamp in seconds
30
* @param crc32 the crc32 signature
31
* @param source_ip_addr the source storage ip address
32
*/
33
	public FileInfo(long file_size, int create_timestamp, int crc32, String source_ip_addr)
34
	{
35
		this.file_size = file_size;
36
		this.create_timestamp = new Date(create_timestamp * 1000L);
37
		this.crc32 = crc32;
38
		this.source_ip_addr = source_ip_addr;
39
	}
40
41
/**
42
* set the source ip address of the file uploaded to
43
* @param source_ip_addr the source ip address
44
*/
45
	public void setSourceIpAddr(String source_ip_addr)
46
	{
47
		this.source_ip_addr = source_ip_addr;
48
	}
49
	
50
/**
51
* get the source ip address of the file uploaded to
52
* @return the source ip address of the file uploaded to
53
*/
54
	public String getSourceIpAddr()
55
	{
56
		return this.source_ip_addr;
57
	}
58
	
59
/**
60
* set the file size
61
* @param file_size the file size
62
*/
63
	public void setFileSize(long file_size)
64
	{
65
		this.file_size = file_size;
66
	}
67
	
68
/**
69
* get the file size
70
* @return the file size
71
*/
72
	public long getFileSize()
73
	{
74
		return this.file_size;
75
	}
76
77
/**
78
* set the create timestamp of the file
79
* @param create_timestamp create timestamp in seconds
80
*/
81
	public void setCreateTimestamp(int create_timestamp)
82
	{
83
		this.create_timestamp = new Date(create_timestamp * 1000L);
84
	}
85
	
86
/**
87
* get the create timestamp of the file
88
* @return the create timestamp of the file
89
*/
90
	public Date getCreateTimestamp()
91
	{
92
		return this.create_timestamp;
93
	}
94
95
/**
96
* set the create timestamp of the file
97
* @param crc32 the crc32 signature
98
*/
99
	public void setCrc32(int crc32)
100
	{
101
		this.crc32 = crc32;
102
	}
103
	
104
/**
105
* get the file CRC32 signature
106
* @return the file CRC32 signature
107
*/
108
	public long getCrc32()
109
	{
110
		return this.crc32;
111
	}
112
	
113
/**
114
* to string
115
* @return string
116
*/
117
	public String toString()
118
	{
119
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
120
		return 	"source_ip_addr = " + this.source_ip_addr + ", " + 
121
		        "file_size = " + this.file_size + ", " +
122
		        "create_timestamp = " + df.format(this.create_timestamp) + ", " +
123
		        "crc32 = " + this.crc32;
124
	}
125
}

+ 554 - 0
src/main/java/org/csource/fastdfs/ProtoCommon.java

@ -0,0 +1,554 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
**/
8
9
package org.csource.fastdfs;
10
11
import org.csource.common.MyException;
12
import org.csource.common.NameValuePair;
13
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.io.UnsupportedEncodingException;
17
import java.net.Socket;
18
import java.security.NoSuchAlgorithmException;
19
import java.util.Arrays;
20
21
/**
22
* protocol common functions
23
* @author Happy Fish / YuQing
24
* @version Version 1.18
25
*/
26
public class ProtoCommon
27
{
28
	/**
29
	* receive package info
30
	*/
31
	public static class RecvPackageInfo
32
	{
33
		public byte errno;
34
		public byte[] body;
35
		
36
		public RecvPackageInfo(byte errno, byte[] body)
37
		{
38
			this.errno = errno;
39
			this.body = body;
40
		}
41
	}
42
	
43
	/**
44
	* receive header info
45
	*/
46
	public static class RecvHeaderInfo
47
	{
48
		public byte errno;
49
		public long body_len;
50
		
51
		public RecvHeaderInfo(byte errno, long body_len)
52
		{
53
			this.errno = errno;
54
			this.body_len = body_len;
55
		}
56
	}
57
	
58
	public static final byte FDFS_PROTO_CMD_QUIT      = 82;
59
	public static final byte TRACKER_PROTO_CMD_SERVER_LIST_GROUP     = 91;
60
	public static final byte TRACKER_PROTO_CMD_SERVER_LIST_STORAGE   = 92;
61
	public static final byte TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE = 93;
62
63
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE = 101;
64
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE = 102;
65
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE = 103;
66
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE = 104;
67
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ALL = 105;
68
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL = 106;
69
	public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL = 107;
70
	public static final byte TRACKER_PROTO_CMD_RESP = 100;
71
	public static final byte FDFS_PROTO_CMD_ACTIVE_TEST = 111;
72
	public static final byte STORAGE_PROTO_CMD_UPLOAD_FILE  = 11;
73
	public static final byte STORAGE_PROTO_CMD_DELETE_FILE	= 12;
74
	public static final byte STORAGE_PROTO_CMD_SET_METADATA	 = 13;
75
	public static final byte STORAGE_PROTO_CMD_DOWNLOAD_FILE = 14;
76
	public static final byte STORAGE_PROTO_CMD_GET_METADATA	 = 15;
77
	public static final byte STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE   = 21;
78
	public static final byte STORAGE_PROTO_CMD_QUERY_FILE_INFO     = 22;
79
	public static final byte STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE= 23;  //create appender file
80
	public static final byte STORAGE_PROTO_CMD_APPEND_FILE         = 24;  //append file
81
	public static final byte STORAGE_PROTO_CMD_MODIFY_FILE         = 34;  //modify appender file
82
	public static final byte STORAGE_PROTO_CMD_TRUNCATE_FILE       = 36;  //truncate appender file
83
84
	public static final byte STORAGE_PROTO_CMD_RESP	 = TRACKER_PROTO_CMD_RESP;
85
86
	public static final byte FDFS_STORAGE_STATUS_INIT        = 0;
87
	public static final byte FDFS_STORAGE_STATUS_WAIT_SYNC   = 1;
88
	public static final byte FDFS_STORAGE_STATUS_SYNCING     = 2;
89
	public static final byte FDFS_STORAGE_STATUS_IP_CHANGED  = 3;
90
	public static final byte FDFS_STORAGE_STATUS_DELETED     = 4;
91
	public static final byte FDFS_STORAGE_STATUS_OFFLINE     = 5;
92
	public static final byte FDFS_STORAGE_STATUS_ONLINE      = 6;
93
	public static final byte FDFS_STORAGE_STATUS_ACTIVE      = 7;
94
	public static final byte FDFS_STORAGE_STATUS_NONE        = 99;
95
	
96
	/**
97
	* for overwrite all old metadata
98
	*/
99
	public static final byte STORAGE_SET_METADATA_FLAG_OVERWRITE = 'O';
100
	
101
	/**
102
	* for replace, insert when the meta item not exist, otherwise update it
103
	*/
104
	public static final byte STORAGE_SET_METADATA_FLAG_MERGE = 'M';
105
106
	public static final int FDFS_PROTO_PKG_LEN_SIZE	= 8;
107
	public static final int FDFS_PROTO_CMD_SIZE		= 1;
108
	public static final int FDFS_GROUP_NAME_MAX_LEN  = 16;
109
	public static final int FDFS_IPADDR_SIZE	 = 16;
110
	public static final int FDFS_DOMAIN_NAME_MAX_SIZE = 128;
111
	public static final int FDFS_VERSION_SIZE = 6;
112
	public static final int FDFS_STORAGE_ID_MAX_SIZE = 16;
113
	
114
	public static final String FDFS_RECORD_SEPERATOR	= "\u0001";
115
	public static final String FDFS_FIELD_SEPERATOR	  = "\u0002";
116
117
	public static final int TRACKER_QUERY_STORAGE_FETCH_BODY_LEN = FDFS_GROUP_NAME_MAX_LEN
118
                        + FDFS_IPADDR_SIZE - 1 + FDFS_PROTO_PKG_LEN_SIZE;
119
	public static final int TRACKER_QUERY_STORAGE_STORE_BODY_LEN = FDFS_GROUP_NAME_MAX_LEN
120
                        + FDFS_IPADDR_SIZE + FDFS_PROTO_PKG_LEN_SIZE;
121
122
	protected static final int PROTO_HEADER_CMD_INDEX	   = FDFS_PROTO_PKG_LEN_SIZE;
123
	protected static final int PROTO_HEADER_STATUS_INDEX = FDFS_PROTO_PKG_LEN_SIZE+1;
124
	
125
	public static final byte FDFS_FILE_EXT_NAME_MAX_LEN  = 6;
126
	public static final byte FDFS_FILE_PREFIX_MAX_LEN    = 16;
127
	public static final byte FDFS_FILE_PATH_LEN          = 10;
128
	public static final byte FDFS_FILENAME_BASE64_LENGTH = 27;
129
	public static final byte FDFS_TRUNK_FILE_INFO_LEN    = 16;
130
	
131
	public static final byte ERR_NO_ENOENT    = 2;
132
	public static final byte ERR_NO_EIO       = 5;
133
	public static final byte ERR_NO_EBUSY     = 16;
134
	public static final byte ERR_NO_EINVAL    = 22;
135
	public static final byte ERR_NO_ENOSPC    = 28;
136
	public static final byte ECONNREFUSED     = 61;
137
	public static final byte ERR_NO_EALREADY  = 114;
138
	
139
	public static final long INFINITE_FILE_SIZE   = 256 * 1024L * 1024 * 1024 * 1024 * 1024L;
140
	public static final long APPENDER_FILE_SIZE   = INFINITE_FILE_SIZE;
141
	public static final long TRUNK_FILE_MARK_SIZE = 512 * 1024L * 1024 * 1024 * 1024 * 1024L;
142
	public static final long NORMAL_LOGIC_FILENAME_LENGTH = FDFS_FILE_PATH_LEN + FDFS_FILENAME_BASE64_LENGTH + FDFS_FILE_EXT_NAME_MAX_LEN + 1;
143
	public static final long TRUNK_LOGIC_FILENAME_LENGTH = NORMAL_LOGIC_FILENAME_LENGTH + FDFS_TRUNK_FILE_INFO_LEN;
144
	
145
	private ProtoCommon()
146
	{
147
	}
148
149
	public static String getStorageStatusCaption(byte status)
150
	{
151
		switch(status)
152
		{
153
			case FDFS_STORAGE_STATUS_INIT:
154
				return "INIT";
155
			case FDFS_STORAGE_STATUS_WAIT_SYNC:
156
				return "WAIT_SYNC";
157
			case FDFS_STORAGE_STATUS_SYNCING:
158
				return "SYNCING";
159
			case FDFS_STORAGE_STATUS_IP_CHANGED:
160
				return "IP_CHANGED";
161
			case FDFS_STORAGE_STATUS_DELETED:
162
				return "DELETED";
163
			case FDFS_STORAGE_STATUS_OFFLINE:
164
				return "OFFLINE";
165
			case FDFS_STORAGE_STATUS_ONLINE:
166
				return "ONLINE";
167
			case FDFS_STORAGE_STATUS_ACTIVE:
168
				return "ACTIVE";
169
			case FDFS_STORAGE_STATUS_NONE:
170
				return "NONE";
171
			default:
172
				return "UNKOWN";
173
	}
174
}
175
176
/**
177
* pack header by FastDFS transfer protocol
178
* @param cmd which command to send
179
* @param pkg_len package body length
180
* @param errno status code, should be (byte)0
181
* @return packed byte buffer
182
*/
183
	public static byte[] packHeader(byte cmd, long pkg_len, byte errno) throws UnsupportedEncodingException
184
	{
185
		byte[] header;
186
		byte[] hex_len;
187
		
188
		header = new byte[FDFS_PROTO_PKG_LEN_SIZE + 2];
189
		Arrays.fill(header, (byte)0);
190
		
191
		hex_len = ProtoCommon.long2buff(pkg_len);
192
		System.arraycopy(hex_len, 0, header, 0, hex_len.length);
193
		header[PROTO_HEADER_CMD_INDEX] = cmd;
194
		header[PROTO_HEADER_STATUS_INDEX] = errno;
195
		return header;
196
	}
197
198
/**
199
* receive pack header
200
* @param in input stream
201
* @param expect_cmd expect response command
202
* @param expect_body_len expect response package body length
203
* @return RecvHeaderInfo: errno and pkg body length
204
*/
205
	public static RecvHeaderInfo recvHeader(InputStream in, byte expect_cmd, long expect_body_len) throws IOException
206
	{
207
		byte[] header;
208
		int bytes;
209
		long pkg_len;
210
		
211
		header = new byte[FDFS_PROTO_PKG_LEN_SIZE + 2];
212
		
213
		if ((bytes=in.read(header)) != header.length)
214
		{
215
			throw new IOException("recv package size " + bytes + " != " + header.length);
216
		}
217
		
218
		if (header[PROTO_HEADER_CMD_INDEX] != expect_cmd)
219
		{
220
			throw new IOException("recv cmd: " + header[PROTO_HEADER_CMD_INDEX] + " is not correct, expect cmd: " + expect_cmd);
221
		}
222
		
223
		if (header[PROTO_HEADER_STATUS_INDEX] != 0)
224
		{
225
			return new RecvHeaderInfo(header[PROTO_HEADER_STATUS_INDEX], 0);
226
		}
227
		
228
		pkg_len = ProtoCommon.buff2long(header, 0);
229
		if (pkg_len < 0)
230
		{
231
			throw new IOException("recv body length: " + pkg_len + " < 0!");
232
		}
233
		
234
		if (expect_body_len >= 0 && pkg_len != expect_body_len)
235
		{
236
			throw new IOException("recv body length: " + pkg_len + " is not correct, expect length: " + expect_body_len);
237
		}
238
		
239
		return new RecvHeaderInfo((byte)0, pkg_len);
240
	}
241
242
/**
243
* receive whole pack
244
* @param in input stream
245
* @param expect_cmd expect response command
246
* @param expect_body_len expect response package body length
247
* @return RecvPackageInfo: errno and reponse body(byte buff)
248
*/
249
	public static RecvPackageInfo recvPackage(InputStream in, byte expect_cmd, long expect_body_len) throws IOException
250
	{
251
		RecvHeaderInfo header = recvHeader(in, expect_cmd, expect_body_len);
252
		if (header.errno != 0)
253
		{
254
			return new RecvPackageInfo(header.errno, null);
255
		}
256
		
257
		byte[] body = new byte[(int)header.body_len];
258
		int totalBytes = 0;
259
		int remainBytes = (int)header.body_len;
260
		int bytes;
261
		
262
		while (totalBytes < header.body_len)
263
		{
264
			if ((bytes=in.read(body, totalBytes, remainBytes)) < 0)
265
			{
266
				break;
267
			}
268
			
269
			totalBytes += bytes;
270
			remainBytes -= bytes;
271
		}
272
		
273
		if (totalBytes != header.body_len)
274
		{
275
			throw new IOException("recv package size " + totalBytes + " != " + header.body_len);
276
		}
277
		
278
		return new RecvPackageInfo((byte)0, body);
279
	}
280
281
/**
282
* split metadata to name value pair array
283
* @param meta_buff metadata
284
* @return name value pair array
285
*/
286
	public static NameValuePair[] split_metadata(String meta_buff)
287
	{
288
		return split_metadata(meta_buff, FDFS_RECORD_SEPERATOR, FDFS_FIELD_SEPERATOR);
289
	}
290
291
/**
292
* split metadata to name value pair array
293
* @param meta_buff metadata
294
* @param recordSeperator record/row seperator
295
* @param filedSeperator field/column seperator
296
* @return name value pair array
297
*/
298
	public static NameValuePair[] split_metadata(String meta_buff,
299
                                                 String  recordSeperator, String  filedSeperator)
300
	{
301
		String[] rows;
302
		String[] cols;
303
		NameValuePair[] meta_list;
304
	
305
		rows = meta_buff.split(recordSeperator);
306
		meta_list = new NameValuePair[rows.length];
307
		for (int i=0; i<rows.length; i++)
308
		{
309
			cols = rows[i].split(filedSeperator, 2);
310
			meta_list[i] = new NameValuePair(cols[0]);
311
			if (cols.length == 2)
312
			{
313
				meta_list[i].setValue(cols[1]);
314
			}
315
		}
316
		
317
		return meta_list;
318
	}
319
320
/**
321
* pack metadata array to string
322
* @param meta_list metadata array
323
* @return packed metadata
324
*/
325
	public static String pack_metadata(NameValuePair[] meta_list)
326
	{		
327
		if (meta_list.length == 0)
328
		{
329
			return "";
330
		}
331
		
332
		StringBuffer sb = new StringBuffer(32 * meta_list.length);
333
		sb.append(meta_list[0].getName()).append(FDFS_FIELD_SEPERATOR).append(meta_list[0].getValue());
334
		for (int i=1; i<meta_list.length; i++)
335
		{
336
			sb.append(FDFS_RECORD_SEPERATOR);
337
			sb.append(meta_list[i].getName()).append(FDFS_FIELD_SEPERATOR).append(meta_list[i].getValue());
338
		}
339
	
340
		return sb.toString();
341
	}
342
343
/**
344
* send quit command to server and close socket
345
* @param sock the Socket object
346
*/
347
	public static void closeSocket(Socket sock) throws IOException
348
	{
349
		byte[] header;
350
		header = packHeader(FDFS_PROTO_CMD_QUIT, 0, (byte)0);
351
		sock.getOutputStream().write(header);
352
		sock.close();
353
	}
354
	
355
/**
356
* send ACTIVE_TEST command to server, test if network is ok and the server is alive
357
* @param sock the Socket object
358
*/
359
	public static boolean activeTest(Socket sock) throws IOException
360
	{
361
		byte[] header;
362
		header = packHeader(FDFS_PROTO_CMD_ACTIVE_TEST, 0, (byte)0);
363
		sock.getOutputStream().write(header);
364
		
365
		RecvHeaderInfo headerInfo = recvHeader(sock.getInputStream(), TRACKER_PROTO_CMD_RESP, 0);
366
		return headerInfo.errno == 0 ? true : false;
367
	}
368
	
369
/**
370
* long convert to buff (big-endian)
371
* @param n long number
372
* @return 8 bytes buff
373
*/
374
	public static byte[] long2buff(long n)
375
	{
376
		byte[] bs;
377
		
378
		bs = new byte[8];
379
		bs[0] = (byte)((n >> 56) & 0xFF);
380
		bs[1] = (byte)((n >> 48) & 0xFF);
381
		bs[2] = (byte)((n >> 40) & 0xFF);
382
		bs[3] = (byte)((n >> 32) & 0xFF);
383
		bs[4] = (byte)((n >> 24) & 0xFF);
384
		bs[5] = (byte)((n >> 16) & 0xFF);
385
		bs[6] = (byte)((n >> 8) & 0xFF);
386
		bs[7] = (byte)(n & 0xFF);
387
		
388
		return bs;
389
	}
390
	
391
/**
392
* buff convert to long
393
* @param bs the buffer (big-endian)
394
* @param offset the start position based 0
395
* @return long number
396
*/
397
	public static long buff2long(byte[] bs, int offset)
398
	{
399
		return  (((long)(bs[offset] >= 0 ? bs[offset] : 256+bs[offset])) << 56) |
400
		        (((long)(bs[offset+1] >= 0 ? bs[offset+1] : 256+bs[offset+1])) << 48) | 
401
		        (((long)(bs[offset+2] >= 0 ? bs[offset+2] : 256+bs[offset+2])) << 40) | 
402
		        (((long)(bs[offset+3] >= 0 ? bs[offset+3] : 256+bs[offset+3])) << 32) | 
403
		        (((long)(bs[offset+4] >= 0 ? bs[offset+4] : 256+bs[offset+4])) << 24) | 
404
		        (((long)(bs[offset+5] >= 0 ? bs[offset+5] : 256+bs[offset+5])) << 16) | 
405
		        (((long)(bs[offset+6] >= 0 ? bs[offset+6] : 256+bs[offset+6])) <<  8) |
406
		         ((long)(bs[offset+7] >= 0 ? bs[offset+7] : 256+bs[offset+7]));
407
	}
408
409
/**
410
* buff convert to int
411
* @param bs the buffer (big-endian)
412
* @param offset the start position based 0
413
* @return int number
414
*/
415
	public static int buff2int(byte[] bs, int offset)
416
	{
417
		return  (((int)(bs[offset] >= 0 ? bs[offset] : 256+bs[offset])) << 24) | 
418
		        (((int)(bs[offset+1] >= 0 ? bs[offset+1] : 256+bs[offset+1])) << 16) | 
419
		        (((int)(bs[offset+2] >= 0 ? bs[offset+2] : 256+bs[offset+2])) <<  8) |
420
		         ((int)(bs[offset+3] >= 0 ? bs[offset+3] : 256+bs[offset+3]));
421
	}
422
	
423
/**
424
* buff convert to ip address
425
* @param bs the buffer (big-endian)
426
* @param offset the start position based 0
427
* @return ip address
428
*/
429
	public static String getIpAddress(byte[] bs, int offset)
430
	{
431
		if (bs[0] == 0 || bs[3] == 0) //storage server ID
432
		{
433
			return "";
434
		}
435
		
436
		int n;
437
		StringBuilder sbResult = new StringBuilder(16);
438
		for (int i=offset; i<offset+4; i++)
439
		{
440
			n = (bs[i] >= 0) ? bs[i] : 256 + bs[i];
441
			if (sbResult.length() > 0)
442
			{
443
				sbResult.append(".");
444
			}
445
			sbResult.append(String.valueOf(n));
446
		}
447
		
448
		return sbResult.toString();
449
	}
450
	
451
 /**
452
* md5 function
453
* @param source the input buffer
454
* @return md5 string
455
*/
456
	public static String md5(byte[] source) throws NoSuchAlgorithmException
457
	{
458
  	char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',  'e', 'f'};
459
    java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
460
    md.update(source);
461
    byte tmp[] = md.digest();
462
    char str[] = new char[32];
463
    int k = 0;
464
    for (int i = 0; i < 16; i++)
465
    {
466
     str[k++] = hexDigits[tmp[i] >>> 4 & 0xf];
467
     str[k++] = hexDigits[tmp[i] & 0xf];
468
    }
469
    
470
  	return new String(str);
471
 }
472
 
473
 /**
474
* get token for file URL
475
* @param remote_filename the filename return by FastDFS server
476
* @param ts unix timestamp, unit: second
477
* @param secret_key the secret key
478
* @return token string
479
*/
480
 public static String getToken(String remote_filename, int ts, String secret_key) throws UnsupportedEncodingException, NoSuchAlgorithmException, MyException
481
 {
482
 	byte[] bsFilename = remote_filename.getBytes(ClientGlobal.g_charset);
483
 	byte[] bsKey = secret_key.getBytes(ClientGlobal.g_charset);
484
 	byte[] bsTimestamp = (new Integer(ts)).toString().getBytes(ClientGlobal.g_charset);
485
 	
486
 	byte[] buff = new byte[bsFilename.length + bsKey.length + bsTimestamp.length];
487
 	System.arraycopy(bsFilename, 0, buff, 0, bsFilename.length);
488
 	System.arraycopy(bsKey, 0, buff, bsFilename.length, bsKey.length);
489
 	System.arraycopy(bsTimestamp, 0, buff, bsFilename.length + bsKey.length, bsTimestamp.length);
490
 	
491
 	return md5(buff);
492
 }
493
 
494
 /**
495
* generate slave filename
496
* @param master_filename the master filename to generate the slave filename
497
* @param prefix_name the prefix name to generate the slave filename
498
* @param ext_name the extension name of slave filename, null for same as the master extension name
499
* @return slave filename string
500
*/
501
 public static String genSlaveFilename(String master_filename, 
502
                String prefix_name, String ext_name) throws MyException
503
 {
504
    String true_ext_name;
505
    int dotIndex;
506
507
    if (master_filename.length() < 28 + FDFS_FILE_EXT_NAME_MAX_LEN)
508
    {
509
            throw new MyException("master filename \"" + master_filename + "\" is invalid");
510
    }
511
512
    dotIndex = master_filename.indexOf('.', master_filename.length() - (FDFS_FILE_EXT_NAME_MAX_LEN + 1));
513
    if (ext_name != null)
514
    {
515
	      if (ext_name.length() == 0)
516
	      {
517
	              true_ext_name = "";
518
	      }
519
	      else if (ext_name.charAt(0) == '.')
520
	      {
521
	              true_ext_name = ext_name;
522
	      }
523
	      else
524
	      {
525
	              true_ext_name = "." + ext_name;
526
	      }
527
    }
528
		else
529
    {
530
	      if (dotIndex < 0)
531
	      {
532
	              true_ext_name = "";
533
	      }
534
	      else
535
	      {
536
	              true_ext_name = master_filename.substring(dotIndex);
537
	      }
538
    }
539
540
    if (true_ext_name.length() == 0 && prefix_name.equals("-m"))
541
    {
542
        throw new MyException("prefix_name \"" + prefix_name + "\" is invalid");
543
    }
544
545
    if (dotIndex < 0)
546
    {
547
        return master_filename + prefix_name + true_ext_name;
548
    }
549
    else
550
    {
551
        return master_filename.substring(0, dotIndex) + prefix_name + true_ext_name;
552
    }
553
	}
554
}

+ 52 - 0
src/main/java/org/csource/fastdfs/ProtoStructDecoder.java

@ -0,0 +1,52 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.lang.reflect.Array;
13
14
/**
15
* C struct body decoder
16
* @author Happy Fish / YuQing
17
* @version Version 1.17
18
*/
19
public class ProtoStructDecoder<T extends StructBase>
20
{	
21
/**
22
* Constructor
23
*/
24
	public ProtoStructDecoder()
25
	{
26
	}
27
	
28
/**
29
* decode byte buffer
30
*/
31
	public T[] decode(byte[] bs, Class<T> clazz, int fieldsTotalSize) throws Exception
32
	{
33
		if (bs.length % fieldsTotalSize != 0)
34
		{
35
			throw new IOException("byte array length: " + bs.length + " is invalid!");
36
		}
37
		
38
		int count = bs.length / fieldsTotalSize;
39
		int offset;
40
		T[] results = (T[])Array.newInstance(clazz, count);
41
		
42
		offset = 0;
43
		for (int i=0; i<results.length; i++)
44
		{
45
			results[i] = clazz.newInstance();
46
			results[i].setFields(bs, offset);
47
			offset += fieldsTotalSize;
48
		}
49
		
50
		return results;
51
	}
52
}

+ 66 - 0
src/main/java/org/csource/fastdfs/ServerInfo.java

@ -0,0 +1,66 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.net.InetSocketAddress;
13
import java.net.Socket;
14
15
/**
16
* Server Info
17
* @author Happy Fish / YuQing
18
* @version Version 1.7
19
*/
20
public class ServerInfo
21
{
22
	protected String ip_addr;
23
	protected int port;
24
	
25
/**
26
* Constructor
27
* @param ip_addr address of the server
28
* @param port the port of the server
29
*/
30
	public ServerInfo(String ip_addr, int port)
31
	{
32
		this.ip_addr = ip_addr;
33
		this.port = port;
34
	}
35
	
36
/**
37
* return the ip address
38
* @return the ip address
39
*/
40
	public String getIpAddr()
41
	{
42
		return this.ip_addr;
43
	}
44
	
45
/**
46
* return the port of the server
47
* @return the port of the server
48
*/
49
	public int getPort()
50
	{
51
		return this.port;
52
	}
53
	
54
/**
55
* connect to server
56
* @return connected Socket object
57
*/
58
	public Socket connect() throws IOException
59
	{
60
		Socket sock = new Socket();
61
		sock.setReuseAddress(true);
62
		sock.setSoTimeout(ClientGlobal.g_network_timeout);
63
		sock.connect(new InetSocketAddress(this.ip_addr, this.port), ClientGlobal.g_connect_timeout);
64
		return sock;
65
	}
66
}

+ 2076 - 0
src/main/java/org/csource/fastdfs/StorageClient.java

@ -0,0 +1,2076 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import org.csource.common.Base64;
12
import org.csource.common.MyException;
13
import org.csource.common.NameValuePair;
14
15
import java.io.*;
16
import java.net.Socket;
17
import java.util.Arrays;
18
19
/**
20
* Storage client for 2 fields file id: group name and filename
21
* @author Happy Fish / YuQing
22
* @version Version 1.24
23
*/
24
public class StorageClient
25
{
26
	/**
27
	* Upload file by file buff
28
	* @author Happy Fish / YuQing
29
	* @version Version 1.12
30
	*/
31
	public static class UploadBuff implements UploadCallback
32
	{
33
		private byte[] fileBuff;
34
		private int offset;
35
		private int length;
36
		
37
		/** 
38
		* constructor
39
		* @param fileBuff the file buff for uploading
40
		*/
41
		public UploadBuff(byte[] fileBuff, int offset, int length)
42
		{
43
			super();
44
			this.fileBuff = fileBuff;
45
			this.offset = offset;
46
			this.length = length;
47
		}
48
	
49
		/**
50
		* send file content callback function, be called only once when the file uploaded
51
		* @param out output stream for writing file content
52
		* @return 0 success, return none zero(errno) if fail
53
		*/
54
		public int send(OutputStream out) throws IOException
55
		{
56
			out.write(this.fileBuff, this.offset, this.length);
57
			
58
			return 0;
59
		}
60
	}
61
	
62
	public final static Base64 base64 = new Base64('-', '_', '.', 0);
63
	protected TrackerServer trackerServer;
64
	protected StorageServer storageServer;
65
	protected byte errno;
66
	
67
/**
68
* constructor using global settings in class ClientGlobal
69
*/
70
	public StorageClient()
71
	{
72
		this.trackerServer = null;
73
		this.storageServer = null;
74
	}
75
	
76
/**
77
* constructor with tracker server and storage server
78
* @param trackerServer the tracker server, can be null
79
* @param storageServer the storage server, can be null
80
*/
81
	public StorageClient(TrackerServer trackerServer, StorageServer storageServer)
82
	{
83
		this.trackerServer = trackerServer;
84
		this.storageServer = storageServer;
85
	}
86
	
87
	public TrackerServer getTracker(){
88
		return trackerServer;
89
	}
90
91
/**
92
* get the error code of last call
93
* @return the error code of last call
94
*/
95
	public byte getErrorCode()
96
	{
97
		return this.errno;
98
	}
99
100
	/**
101
	* upload file to storage server (by file name)
102
	* @param local_filename local filename to upload
103
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
104
	* @param meta_list meta info array
105
	* @return  2 elements string array if success:<br>
106
	*           <ul><li>results[0]: the group name to store the file </li></ul>
107
	*           <ul><li>results[1]: the new created filename</li></ul>
108
	*         return null if fail
109
	*/
110
	public String[] upload_file(String local_filename, String file_ext_name, 
111
	       NameValuePair[] meta_list) throws IOException, MyException
112
	{
113
		final String group_name = null;
114
		return this.upload_file(group_name, local_filename, file_ext_name, meta_list);
115
	}
116
	
117
	/**
118
	* upload file to storage server (by file name)
119
	* @param group_name the group name to upload file to, can be empty
120
	* @param local_filename local filename to upload
121
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
122
	* @param meta_list meta info array
123
	* @return  2 elements string array if success:<br>
124
	*           <ul><li>results[0]: the group name to store the file </li></ul>
125
	*           <ul><li>results[1]: the new created filename</li></ul>
126
	*         return null if fail
127
	*/
128
	protected String[] upload_file(String group_name, String local_filename, String file_ext_name, 
129
	       NameValuePair[] meta_list) throws IOException, MyException
130
	{
131
		final byte cmd = ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_FILE;
132
		return this.upload_file(cmd, group_name, local_filename, file_ext_name, meta_list);
133
	}
134
135
	/**
136
	* upload file to storage server (by file name)
137
	* @param cmd the command
138
	* @param group_name the group name to upload file to, can be empty
139
	* @param local_filename local filename to upload
140
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
141
	* @param meta_list meta info array
142
	* @return  2 elements string array if success:<br>
143
	*           <ul><li>results[0]: the group name to store the file </li></ul>
144
	*           <ul><li>results[1]: the new created filename</li></ul>
145
	*         return null if fail
146
	*/
147
	protected String[] upload_file(byte cmd, String group_name, String local_filename, String file_ext_name, 
148
	       NameValuePair[] meta_list) throws IOException, MyException
149
	{
150
		File f = new File(local_filename);
151
		FileInputStream fis = new FileInputStream(f);
152
		
153
		if (file_ext_name == null)
154
		{
155
			int nPos = local_filename.lastIndexOf('.');
156
			if (nPos > 0 && local_filename.length() - nPos <= ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN + 1)
157
			{
158
				file_ext_name = local_filename.substring(nPos+1);
159
			}
160
		}
161
		
162
		try
163
		{
164
		  return this.do_upload_file(cmd, group_name, null, null, file_ext_name, 
165
		           f.length(), new UploadStream(fis, f.length()), meta_list);
166
		}
167
		finally
168
		{
169
			fis.close();
170
		}
171
	}
172
173
	/**
174
	* upload file to storage server (by file buff)
175
	* @param file_buff file content/buff
176
	* @param offset start offset of the buff
177
	* @param length the length of buff to upload
178
	* @param file_ext_name file ext name, do not include dot(.)
179
	*	@param meta_list meta info array
180
	* @return  2 elements string array if success:<br>
181
	*           <ul><li>results[0]: the group name to store the file</li></ul>
182
	*           <ul><li>results[1]: the new created filename</li></ul>
183
	*         return null if fail
184
	*/
185
	public String[] upload_file(byte[] file_buff,	int offset, int length, String file_ext_name, 
186
	       NameValuePair[] meta_list) throws IOException, MyException
187
	{
188
		final String group_name = null;
189
		return this.upload_file(group_name, file_buff, offset, length, file_ext_name, meta_list);
190
	}
191
	
192
	/**
193
	* upload file to storage server (by file buff)
194
	* @param group_name the group name to upload file to, can be empty
195
	* @param file_buff file content/buff
196
	* @param offset start offset of the buff
197
	* @param length the length of buff to upload
198
	* @param file_ext_name file ext name, do not include dot(.)
199
	*	@param meta_list meta info array
200
	* @return  2 elements string array if success:<br>
201
	*           <ul><li>results[0]: the group name to store the file</li></ul>
202
	*           <ul><li>results[1]: the new created filename</li></ul>
203
	*         return null if fail
204
	*/
205
	public String[] upload_file(String group_name, byte[] file_buff, int offset, int length,	
206
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
207
	{
208
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_FILE, group_name, null, null, file_ext_name, 
209
		           length, new UploadBuff(file_buff, offset, length), meta_list);
210
	}
211
	
212
	/**
213
	* upload file to storage server (by file buff)
214
	* @param file_buff file content/buff
215
	* @param file_ext_name file ext name, do not include dot(.)
216
	*	@param meta_list meta info array
217
	* @return  2 elements string array if success:<br>
218
	*           <ul><li>results[0]: the group name to store the file</li></ul>
219
	*           <ul><li>results[1]: the new created filename</li></ul>
220
	*         return null if fail
221
	*/
222
	public String[] upload_file(byte[] file_buff, String file_ext_name, 
223
	       NameValuePair[] meta_list) throws IOException, MyException
224
	{
225
		final String group_name = null;
226
		return this.upload_file(group_name, file_buff, 0, file_buff.length, file_ext_name, meta_list);
227
	}
228
	
229
	/**
230
	* upload file to storage server (by file buff)
231
	* @param group_name the group name to upload file to, can be empty
232
	* @param file_buff file content/buff
233
	* @param file_ext_name file ext name, do not include dot(.)
234
	*	@param meta_list meta info array
235
	* @return  2 elements string array if success:<br>
236
	*           <ul><li>results[0]: the group name to store the file</li></ul>
237
	*           <ul><li>results[1]: the new created filename</li></ul>
238
	*         return null if fail
239
	*/
240
	public String[] upload_file(String group_name, byte[] file_buff,	
241
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
242
	{
243
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_FILE, group_name, null, null, file_ext_name, 
244
		           file_buff.length, new UploadBuff(file_buff, 0, file_buff.length), meta_list);
245
	}
246
	
247
	
248
	/**
249
	* upload file to storage server (by callback)
250
	* @param group_name the group name to upload file to, can be empty
251
	* @param file_size the file size
252
	* @param callback the write data callback object
253
	* @param file_ext_name file ext name, do not include dot(.)
254
	*	@param meta_list meta info array
255
	* @return  2 elements string array if success:<br>
256
	*           <ul><li>results[0]: the group name to store the file</li></ul>
257
	*           <ul><li>results[1]: the new created filename</li></ul>
258
	*         return null if fail
259
	*/
260
	public String[] upload_file(String group_name, long file_size, UploadCallback callback, 
261
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
262
	{
263
		final String master_filename = null;
264
		final String prefix_name = null;
265
		
266
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_FILE, group_name, master_filename, prefix_name, 
267
           file_ext_name, file_size, callback, meta_list);
268
	}
269
	
270
	/**
271
	* upload file to storage server (by file name, slave file mode)
272
	* @param group_name the group name of master file
273
	* @param master_filename the master file name to generate the slave file
274
	* @param prefix_name the prefix name to generate the slave file
275
	* @param local_filename local filename to upload
276
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
277
	* @param meta_list meta info array
278
	* @return  2 elements string array if success:<br>
279
	*           <ul><li>results[0]: the group name to store the file </li></ul>
280
	*           <ul><li>results[1]: the new created filename</li></ul>
281
	*         return null if fail
282
	*/
283
	public String[] upload_file(String group_name, String master_filename, String prefix_name, 
284
         String local_filename, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
285
	{
286
		if ((group_name == null || group_name.length() == 0) || 
287
		    (master_filename == null || master_filename.length() == 0) ||
288
		    (prefix_name == null))
289
		{
290
			throw new MyException("invalid arguement");
291
		}
292
		
293
		File f = new File(local_filename);
294
		FileInputStream fis = new FileInputStream(f);
295
		
296
		if (file_ext_name == null)
297
		{
298
			int nPos = local_filename.lastIndexOf('.');
299
			if (nPos > 0 && local_filename.length() - nPos <= ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN + 1)
300
			{
301
				file_ext_name = local_filename.substring(nPos+1);
302
			}
303
		}
304
		
305
		try
306
		{
307
		  return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE, group_name, master_filename, prefix_name, 
308
		                           file_ext_name, f.length(), new UploadStream(fis, f.length()), meta_list);
309
    }
310
    finally
311
    {
312
    	fis.close();
313
    }
314
	}
315
	
316
	/**
317
	* upload file to storage server (by file buff, slave file mode)
318
	* @param group_name the group name of master file
319
	* @param master_filename the master file name to generate the slave file
320
	* @param prefix_name the prefix name to generate the slave file
321
	* @param file_buff file content/buff
322
	* @param file_ext_name file ext name, do not include dot(.)
323
	*	@param meta_list meta info array
324
	* @return  2 elements string array if success:<br>
325
	*           <ul><li>results[0]: the group name to store the file</li></ul>
326
	*           <ul><li>results[1]: the new created filename</li></ul>
327
	*         return null if fail
328
	*/
329
	public String[] upload_file(String group_name, String master_filename, String prefix_name, 
330
	       byte[] file_buff, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
331
	{
332
		if ((group_name == null || group_name.length() == 0) || 
333
		    (master_filename == null || master_filename.length() == 0) ||
334
		    (prefix_name == null))
335
		{
336
			throw new MyException("invalid arguement");
337
		}
338
339
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE, group_name, master_filename, prefix_name, 
340
		                           file_ext_name, file_buff.length, new UploadBuff(file_buff, 0, file_buff.length), meta_list);
341
	}
342
	
343
	/**
344
	* upload file to storage server (by file buff, slave file mode)
345
	* @param group_name the group name of master file
346
	* @param master_filename the master file name to generate the slave file
347
	* @param prefix_name the prefix name to generate the slave file
348
	* @param file_buff file content/buff
349
	* @param offset start offset of the buff
350
	* @param length the length of buff to upload
351
	* @param file_ext_name file ext name, do not include dot(.)
352
	*	@param meta_list meta info array
353
	* @return  2 elements string array if success:<br>
354
	*           <ul><li>results[0]: the group name to store the file</li></ul>
355
	*           <ul><li>results[1]: the new created filename</li></ul>
356
	*         return null if fail
357
	*/
358
	public String[] upload_file(String group_name, String master_filename, String prefix_name, 
359
	       byte[] file_buff, int offset, int length, String file_ext_name, 
360
	       NameValuePair[] meta_list) throws IOException, MyException
361
	{
362
		if ((group_name == null || group_name.length() == 0) || 
363
		    (master_filename == null || master_filename.length() == 0) ||
364
		    (prefix_name == null))
365
		{
366
			throw new MyException("invalid arguement");
367
		}
368
369
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE, group_name, master_filename, prefix_name, 
370
		            file_ext_name, length, new UploadBuff(file_buff, offset, length), meta_list);
371
	}
372
373
	/**
374
	* upload file to storage server (by callback, slave file mode)
375
	* @param group_name the group name to upload file to, can be empty
376
	* @param master_filename the master file name to generate the slave file
377
	* @param prefix_name the prefix name to generate the slave file
378
	* @param file_size the file size
379
	* @param callback the write data callback object
380
	* @param file_ext_name file ext name, do not include dot(.)
381
	*	@param meta_list meta info array
382
	* @return  2 elements string array if success:<br>
383
	*           <ul><li>results[0]: the group name to store the file</li></ul>
384
	*           <ul><li>results[1]: the new created filename</li></ul>
385
	*         return null if fail
386
	*/
387
	public String[] upload_file(String group_name, String master_filename, 
388
	       String prefix_name, long file_size, UploadCallback callback, 
389
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
390
	{
391
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE, group_name, master_filename, prefix_name, 
392
           file_ext_name, file_size, callback, meta_list);
393
	}
394
	
395
	/**
396
	* upload appender file to storage server (by file name)
397
	* @param local_filename local filename to upload
398
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
399
	* @param meta_list meta info array
400
	* @return  2 elements string array if success:<br>
401
	*           <ul><li>results[0]: the group name to store the file </li></ul>
402
	*           <ul><li>results[1]: the new created filename</li></ul>
403
	*         return null if fail
404
	*/
405
	public String[] upload_appender_file(String local_filename, String file_ext_name, 
406
	       NameValuePair[] meta_list) throws IOException, MyException
407
	{
408
		final String group_name = null;
409
		return this.upload_appender_file(group_name, local_filename, file_ext_name, meta_list);
410
	}
411
	
412
	/**
413
	* upload appender file to storage server (by file name)
414
	* @param group_name the group name to upload file to, can be empty
415
	* @param local_filename local filename to upload
416
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
417
	* @param meta_list meta info array
418
	* @return  2 elements string array if success:<br>
419
	*           <ul><li>results[0]: the group name to store the file </li></ul>
420
	*           <ul><li>results[1]: the new created filename</li></ul>
421
	*         return null if fail
422
	*/
423
	protected String[] upload_appender_file(String group_name, String local_filename, String file_ext_name, 
424
	       NameValuePair[] meta_list) throws IOException, MyException
425
	{
426
		final byte cmd = ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE;
427
		return this.upload_file(cmd, group_name, local_filename, file_ext_name, meta_list);
428
	}
429
430
	/**
431
	* upload appender file to storage server (by file buff)
432
	* @param file_buff file content/buff
433
	* @param offset start offset of the buff
434
	* @param length the length of buff to upload
435
	* @param file_ext_name file ext name, do not include dot(.)
436
	*	@param meta_list meta info array
437
	* @return  2 elements string array if success:<br>
438
	*           <ul><li>results[0]: the group name to store the file</li></ul>
439
	*           <ul><li>results[1]: the new created filename</li></ul>
440
	*         return null if fail
441
	*/
442
	public String[] upload_appender_file(byte[] file_buff,	int offset, int length, String file_ext_name, 
443
	       NameValuePair[] meta_list) throws IOException, MyException
444
	{
445
		final String group_name = null;
446
		return this.upload_appender_file(group_name, file_buff, offset, length, file_ext_name, meta_list);
447
	}
448
	
449
	/**
450
	* upload appender file to storage server (by file buff)
451
	* @param group_name the group name to upload file to, can be empty
452
	* @param file_buff file content/buff
453
	* @param offset start offset of the buff
454
	* @param length the length of buff to upload
455
	* @param file_ext_name file ext name, do not include dot(.)
456
	*	@param meta_list meta info array
457
	* @return  2 elements string array if success:<br>
458
	*           <ul><li>results[0]: the group name to store the file</li></ul>
459
	*           <ul><li>results[1]: the new created filename</li></ul>
460
	*         return null if fail
461
	*/
462
	public String[] upload_appender_file(String group_name, byte[] file_buff, int offset, int length,	
463
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
464
	{
465
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE, group_name, null, null, file_ext_name, 
466
		           length, new UploadBuff(file_buff, offset, length), meta_list);
467
	}
468
	
469
	/**
470
	* upload appender file to storage server (by file buff)
471
	* @param file_buff file content/buff
472
	* @param file_ext_name file ext name, do not include dot(.)
473
	*	@param meta_list meta info array
474
	* @return  2 elements string array if success:<br>
475
	*           <ul><li>results[0]: the group name to store the file</li></ul>
476
	*           <ul><li>results[1]: the new created filename</li></ul>
477
	*         return null if fail
478
	*/
479
	public String[] upload_appender_file(byte[] file_buff, String file_ext_name, 
480
	       NameValuePair[] meta_list) throws IOException, MyException
481
	{
482
		final String group_name = null;
483
		return this.upload_appender_file(group_name, file_buff, 0, file_buff.length, file_ext_name, meta_list);
484
	}
485
	
486
	/**
487
	* upload appender file to storage server (by file buff)
488
	* @param group_name the group name to upload file to, can be empty
489
	* @param file_buff file content/buff
490
	* @param file_ext_name file ext name, do not include dot(.)
491
	*	@param meta_list meta info array
492
	* @return  2 elements string array if success:<br>
493
	*           <ul><li>results[0]: the group name to store the file</li></ul>
494
	*           <ul><li>results[1]: the new created filename</li></ul>
495
	*         return null if fail
496
	*/
497
	public String[] upload_appender_file(String group_name, byte[] file_buff,	
498
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
499
	{
500
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE, group_name, null, null, file_ext_name, 
501
		           file_buff.length, new UploadBuff(file_buff, 0, file_buff.length), meta_list);
502
	}
503
	
504
	/**
505
	* upload appender file to storage server (by callback)
506
	* @param group_name the group name to upload file to, can be empty
507
	* @param file_size the file size
508
	* @param callback the write data callback object
509
	* @param file_ext_name file ext name, do not include dot(.)
510
	*	@param meta_list meta info array
511
	* @return  2 elements string array if success:<br>
512
	*           <ul><li>results[0]: the group name to store the file</li></ul>
513
	*           <ul><li>results[1]: the new created filename</li></ul>
514
	*         return null if fail
515
	*/
516
	public String[] upload_appender_file(String group_name, long file_size, UploadCallback callback, 
517
	       String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
518
	{
519
		final String master_filename = null;
520
		final String prefix_name = null;
521
		
522
		return this.do_upload_file(ProtoCommon.STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE, group_name, master_filename, prefix_name, 
523
           file_ext_name, file_size, callback, meta_list);
524
	}
525
526
	/**
527
	* append file to storage server (by file name)
528
	* @param group_name the group name of appender file
529
	* @param appender_filename the appender filename
530
	* @param local_filename local filename to append
531
	* @return 0 for success, != 0 for error (error no)
532
	*/
533
	public int append_file(String group_name, String appender_filename, String local_filename) throws IOException, MyException
534
	{
535
		File f = new File(local_filename);
536
		FileInputStream fis = new FileInputStream(f);
537
		
538
		try
539
		{
540
			return this.do_append_file(group_name, appender_filename, f.length(), new UploadStream(fis, f.length()));
541
		}
542
		finally
543
		{
544
			fis.close();
545
		}
546
	}
547
	
548
	/**
549
	* append file to storage server (by file buff)
550
	* @param group_name the group name of appender file
551
	* @param appender_filename the appender filename
552
	* @param file_buff file content/buff
553
	* @return 0 for success, != 0 for error (error no)
554
	*/
555
	public int append_file(String group_name, String appender_filename, byte[] file_buff) throws IOException, MyException
556
	{
557
		return this.do_append_file(group_name, appender_filename, file_buff.length, new UploadBuff(file_buff, 0, file_buff.length));
558
	}
559
	
560
	/**
561
	* append file to storage server (by file buff)
562
	* @param group_name the group name of appender file
563
	* @param appender_filename the appender filename
564
	* @param file_buff file content/buff
565
	* @param offset start offset of the buff
566
	* @param length the length of buff to append
567
	* @return 0 for success, != 0 for error (error no)
568
	*/
569
	public int append_file(String group_name, String appender_filename, 
570
	       byte[] file_buff, int offset, int length) throws IOException, MyException
571
	{
572
		return this.do_append_file(group_name, appender_filename, length, new UploadBuff(file_buff, offset, length));
573
	}
574
575
	/**
576
	* append file to storage server (by callback)
577
	* @param group_name the group name to append file to
578
	* @param appender_filename the appender filename
579
	* @param file_size the file size
580
	* @param callback the write data callback object
581
	* @return 0 for success, != 0 for error (error no)
582
	*/
583
	public int append_file(String group_name, String appender_filename, 
584
	       long file_size, UploadCallback callback) throws IOException, MyException
585
	{
586
		return this.do_append_file(group_name, appender_filename, file_size, callback);
587
	}
588
589
	/**
590
	* modify appender file to storage server (by file name)
591
	* @param group_name the group name of appender file
592
	* @param appender_filename the appender filename
593
	* @param file_offset the offset of appender file
594
	* @param local_filename local filename to append
595
	* @return 0 for success, != 0 for error (error no)
596
	*/
597
	public int modify_file(String group_name, String appender_filename, 
598
			long file_offset, String local_filename) throws IOException, MyException
599
	{
600
		File f = new File(local_filename);
601
		FileInputStream fis = new FileInputStream(f);
602
		
603
		try
604
		{
605
		  return this.do_modify_file(group_name, appender_filename, file_offset, 
606
			  	f.length(), new UploadStream(fis, f.length()));
607
		}
608
		finally
609
		{
610
			fis.close();
611
		}
612
	}
613
	
614
	/**
615
	* modify appender file to storage server (by file buff)
616
	* @param group_name the group name of appender file
617
	* @param appender_filename the appender filename
618
	* @param file_offset the offset of appender file
619
	* @param file_buff file content/buff
620
	* @return 0 for success, != 0 for error (error no)
621
	*/
622
	public int modify_file(String group_name, String appender_filename, 
623
			long file_offset, byte[] file_buff) throws IOException, MyException
624
	{
625
		return this.do_modify_file(group_name, appender_filename, file_offset, 
626
				file_buff.length, new UploadBuff(file_buff, 0, file_buff.length));
627
	}
628
	
629
	/**
630
	* modify appender file to storage server (by file buff)
631
	* @param group_name the group name of appender file
632
	* @param appender_filename the appender filename
633
	* @param file_offset the offset of appender file
634
	* @param file_buff file content/buff
635
	* @param buffer_offset start offset of the buff
636
	* @param buffer_length the length of buff to modify
637
	* @return 0 for success, != 0 for error (error no)
638
	*/
639
	public int modify_file(String group_name, String appender_filename, 
640
	       long file_offset, byte[] file_buff, int buffer_offset, int buffer_length) throws IOException, MyException
641
	{
642
		return this.do_modify_file(group_name, appender_filename, file_offset, 
643
				buffer_length, new UploadBuff(file_buff, buffer_offset, buffer_length));
644
	}
645
646
	/**
647
	* modify appender file to storage server (by callback)
648
	* @param group_name the group name to modify file to
649
	* @param appender_filename the appender filename
650
	* @param file_offset the offset of appender file
651
	* @param modify_size the modify size
652
	* @param callback the write data callback object
653
	* @return 0 for success, != 0 for error (error no)
654
	*/
655
	public int modify_file(String group_name, String appender_filename, 
656
	       long file_offset, long modify_size, UploadCallback callback) throws IOException, MyException
657
	{
658
		return this.do_modify_file(group_name, appender_filename, file_offset, 
659
				modify_size, callback);
660
	}
661
	
662
	/**
663
	* upload file to storage server
664
	* @param cmd the command code
665
	* @param group_name the group name to upload file to, can be empty
666
	* @param master_filename the master file name to generate the slave file
667
	* @param prefix_name the prefix name to generate the slave file
668
  * @param file_ext_name file ext name, do not include dot(.)
669
	* @param file_size the file size
670
	* @param callback the write data callback object
671
	*	@param meta_list meta info array
672
	* @return  2 elements string array if success:<br>
673
	*          <ul><li> results[0]: the group name to store the file</li></ul>
674
	*          <ul><li> results[1]: the new created filename</li></ul> 
675
	*         return null if fail
676
	*/
677
	protected String[] do_upload_file(byte cmd, String group_name, String master_filename, 
678
	         String prefix_name, String file_ext_name, long file_size, UploadCallback callback, 
679
           NameValuePair[] meta_list) throws IOException, MyException
680
	{
681
		byte[] header;
682
		byte[] ext_name_bs;
683
		String new_group_name;
684
		String remote_filename;
685
		boolean bNewConnection;
686
		Socket storageSocket;
687
		byte[] sizeBytes;
688
		byte[] hexLenBytes;
689
		byte[] masterFilenameBytes;
690
		boolean bUploadSlave;
691
		int offset;
692
		long body_len;
693
694
		bUploadSlave = ((group_name != null && group_name.length() > 0) && 
695
		                (master_filename != null && master_filename.length() > 0) &&
696
		                (prefix_name != null));
697
		if (bUploadSlave)
698
		{
699
			bNewConnection = this.newUpdatableStorageConnection(group_name, master_filename);
700
		}
701
		else
702
		{
703
			bNewConnection = this.newWritableStorageConnection(group_name);
704
		}
705
		
706
		try
707
		{
708
			storageSocket = this.storageServer.getSocket();
709
			
710
			ext_name_bs = new byte[ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN];
711
			Arrays.fill(ext_name_bs, (byte)0);
712
			if (file_ext_name != null && file_ext_name.length() > 0)
713
			{
714
				byte[] bs = file_ext_name.getBytes(ClientGlobal.g_charset);
715
				int ext_name_len = bs.length;
716
				if (ext_name_len > ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN)
717
				{
718
					ext_name_len = ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN;
719
				}
720
				System.arraycopy(bs, 0, ext_name_bs, 0, ext_name_len);
721
			}
722
			
723
			if (bUploadSlave)
724
			{
725
				masterFilenameBytes = master_filename.getBytes(ClientGlobal.g_charset);
726
				
727
				sizeBytes = new byte[2 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE];
728
				body_len = sizeBytes.length + ProtoCommon.FDFS_FILE_PREFIX_MAX_LEN + ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN
729
				         + masterFilenameBytes.length + file_size;
730
				
731
				hexLenBytes = ProtoCommon.long2buff(master_filename.length());
732
				System.arraycopy(hexLenBytes, 0, sizeBytes, 0, hexLenBytes.length);
733
				offset = hexLenBytes.length;
734
			}
735
			else
736
			{
737
				masterFilenameBytes = null;
738
				sizeBytes = new byte[1 + 1 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE];
739
        body_len = sizeBytes.length + ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN + file_size;
740
741
				sizeBytes[0] = (byte)this.storageServer.getStorePathIndex();
742
				offset = 1;
743
			}
744
			
745
			hexLenBytes = ProtoCommon.long2buff(file_size);
746
			System.arraycopy(hexLenBytes, 0, sizeBytes, offset, hexLenBytes.length);
747
			
748
			OutputStream out = storageSocket.getOutputStream();
749
			header = ProtoCommon.packHeader(cmd, body_len, (byte)0);
750
			byte[] wholePkg = new byte[(int)(header.length + body_len - file_size)];
751
			System.arraycopy(header, 0, wholePkg, 0, header.length);
752
			System.arraycopy(sizeBytes, 0, wholePkg, header.length, sizeBytes.length);
753
			offset = header.length + sizeBytes.length;
754
			if (bUploadSlave)
755
			{
756
				byte[] prefix_name_bs = new byte[ProtoCommon.FDFS_FILE_PREFIX_MAX_LEN];
757
				byte[] bs = prefix_name.getBytes(ClientGlobal.g_charset);
758
				int prefix_name_len = bs.length;
759
				Arrays.fill(prefix_name_bs, (byte)0);
760
				if (prefix_name_len > ProtoCommon.FDFS_FILE_PREFIX_MAX_LEN)
761
				{
762
					prefix_name_len = ProtoCommon.FDFS_FILE_PREFIX_MAX_LEN;
763
				}
764
				if (prefix_name_len > 0)
765
				{
766
					System.arraycopy(bs, 0, prefix_name_bs, 0, prefix_name_len);
767
				}
768
				
769
				System.arraycopy(prefix_name_bs, 0, wholePkg, offset, prefix_name_bs.length);
770
				offset += prefix_name_bs.length;
771
			}
772
			
773
			System.arraycopy(ext_name_bs, 0, wholePkg, offset, ext_name_bs.length);
774
			offset += ext_name_bs.length;
775
			
776
			if (bUploadSlave)
777
			{
778
				System.arraycopy(masterFilenameBytes, 0, wholePkg, offset, masterFilenameBytes.length);
779
				offset += masterFilenameBytes.length;
780
			}
781
			
782
			out.write(wholePkg);
783
			
784
			if ((this.errno=(byte)callback.send(out)) != 0)
785
			{
786
				return null;
787
			}
788
			
789
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
790
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, -1);
791
			this.errno = pkgInfo.errno;
792
			if (pkgInfo.errno != 0)
793
			{
794
				return null;
795
			}
796
			
797
			if (pkgInfo.body.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN)
798
			{
799
				throw new MyException("body length: " + pkgInfo.body.length + " <= " + ProtoCommon.FDFS_GROUP_NAME_MAX_LEN);
800
			}
801
	
802
			new_group_name = new String(pkgInfo.body, 0, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN).trim();
803
			remote_filename = new String(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN, pkgInfo.body.length - ProtoCommon.FDFS_GROUP_NAME_MAX_LEN);
804
			String[] results = new String[2];
805
			results[0] = new_group_name;
806
			results[1] = remote_filename;
807
			
808
			if (meta_list == null || meta_list.length == 0)
809
			{
810
				return results;
811
			}
812
			
813
			int result = 0;
814
			try
815
			{
816
				result = this.set_metadata(new_group_name, remote_filename, 
817
								meta_list, ProtoCommon.STORAGE_SET_METADATA_FLAG_OVERWRITE);
818
			}
819
			catch(IOException ex)
820
			{
821
				result = 5;
822
				throw ex;
823
			}
824
			finally
825
			{
826
				if (result != 0)
827
				{
828
					this.errno = (byte)result;
829
					this.delete_file(new_group_name, remote_filename);
830
					return null;
831
				}
832
			}
833
			
834
			return results;
835
		}
836
		catch(IOException ex)
837
		{
838
			if (!bNewConnection)
839
			{
840
				try
841
				{
842
					this.storageServer.close();
843
				}
844
				catch(IOException ex1)
845
				{
846
					ex1.printStackTrace();
847
				}
848
				finally
849
				{
850
					this.storageServer = null;
851
				}
852
			}
853
			
854
			throw ex;
855
		}
856
		finally
857
		{
858
			if (bNewConnection)
859
			{
860
				try
861
				{
862
					this.storageServer.close();
863
				}
864
				catch(IOException ex1)
865
				{
866
					ex1.printStackTrace();
867
				}
868
				finally
869
				{
870
					this.storageServer = null;
871
				}
872
			}
873
		}
874
	}
875
876
	/**
877
	* append file to storage server
878
	* @param group_name the group name of appender file
879
	* @param appender_filename the appender filename
880
	* @param file_size the file size
881
	* @param callback the write data callback object
882
	* @return return true for success, false for fail
883
	*/
884
	protected int do_append_file(String group_name, String appender_filename, 
885
	         long file_size, UploadCallback callback) throws IOException, MyException
886
	{
887
		byte[] header;
888
		boolean bNewConnection;
889
		Socket storageSocket;
890
		byte[] hexLenBytes;
891
		byte[] appenderFilenameBytes;
892
		int offset;
893
		long body_len;
894
895
		if ((group_name == null || group_name.length() == 0) || 
896
		    (appender_filename == null || appender_filename.length() == 0))
897
		{
898
			this.errno = ProtoCommon.ERR_NO_EINVAL;
899
			return this.errno;
900
		}
901
		
902
		bNewConnection = this.newUpdatableStorageConnection(group_name, appender_filename);
903
		
904
		try
905
		{
906
			storageSocket = this.storageServer.getSocket();
907
						
908
			appenderFilenameBytes = appender_filename.getBytes(ClientGlobal.g_charset);
909
			body_len = 2 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE + appenderFilenameBytes.length + file_size;
910
			
911
			header = ProtoCommon.packHeader(ProtoCommon.STORAGE_PROTO_CMD_APPEND_FILE, body_len, (byte)0);
912
			byte[] wholePkg = new byte[(int)(header.length + body_len - file_size)];
913
			System.arraycopy(header, 0, wholePkg, 0, header.length);
914
			offset = header.length;
915
			
916
			hexLenBytes = ProtoCommon.long2buff(appender_filename.length());
917
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
918
			offset += hexLenBytes.length;
919
			
920
			hexLenBytes = ProtoCommon.long2buff(file_size);
921
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
922
			offset += hexLenBytes.length;
923
			
924
			OutputStream out = storageSocket.getOutputStream();
925
			
926
			System.arraycopy(appenderFilenameBytes, 0, wholePkg, offset, appenderFilenameBytes.length);
927
			offset += appenderFilenameBytes.length;
928
			
929
			out.write(wholePkg);
930
			if ((this.errno=(byte)callback.send(out)) != 0)
931
			{
932
				return this.errno;
933
			}
934
			
935
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
936
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, 0);
937
			this.errno = pkgInfo.errno;
938
			if (pkgInfo.errno != 0)
939
			{
940
				return this.errno;
941
			}
942
			
943
			return 0;
944
		}
945
		catch(IOException ex)
946
		{
947
			if (!bNewConnection)
948
			{
949
				try
950
				{
951
					this.storageServer.close();
952
				}
953
				catch(IOException ex1)
954
				{
955
					ex1.printStackTrace();
956
				}
957
				finally
958
				{
959
					this.storageServer = null;
960
				}
961
			}
962
			
963
			throw ex;
964
		}
965
		finally
966
		{
967
			if (bNewConnection)
968
			{
969
				try
970
				{
971
					this.storageServer.close();
972
				}
973
				catch(IOException ex1)
974
				{
975
					ex1.printStackTrace();
976
				}
977
				finally
978
				{
979
					this.storageServer = null;
980
				}
981
			}
982
		}
983
	}
984
985
	/**
986
	* modify appender file to storage server
987
	* @param group_name the group name of appender file
988
	* @param appender_filename the appender filename
989
	* @param file_offset the offset of appender file
990
	* @param modify_size the modify size
991
	* @param callback the write data callback object
992
	* @return return true for success, false for fail
993
	*/
994
	protected int do_modify_file(String group_name, String appender_filename, 
995
	         long file_offset, long modify_size, UploadCallback callback) throws IOException, MyException
996
	{
997
		byte[] header;
998
		boolean bNewConnection;
999
		Socket storageSocket;
1000
		byte[] hexLenBytes;
1001
		byte[] appenderFilenameBytes;
1002
		int offset;
1003
		long body_len;
1004
1005
		if ((group_name == null || group_name.length() == 0) || 
1006
		    (appender_filename == null || appender_filename.length() == 0))
1007
		{
1008
			this.errno = ProtoCommon.ERR_NO_EINVAL;
1009
			return this.errno;
1010
		}
1011
		
1012
		bNewConnection = this.newUpdatableStorageConnection(group_name, appender_filename);
1013
		
1014
		try
1015
		{
1016
			storageSocket = this.storageServer.getSocket();
1017
						
1018
			appenderFilenameBytes = appender_filename.getBytes(ClientGlobal.g_charset);
1019
			body_len = 3 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE + appenderFilenameBytes.length + modify_size;
1020
			
1021
			header = ProtoCommon.packHeader(ProtoCommon.STORAGE_PROTO_CMD_MODIFY_FILE, body_len, (byte)0);
1022
			byte[] wholePkg = new byte[(int)(header.length + body_len - modify_size)];
1023
			System.arraycopy(header, 0, wholePkg, 0, header.length);
1024
			offset = header.length;
1025
			
1026
			hexLenBytes = ProtoCommon.long2buff(appender_filename.length());
1027
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
1028
			offset += hexLenBytes.length;
1029
1030
			hexLenBytes = ProtoCommon.long2buff(file_offset);
1031
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
1032
			offset += hexLenBytes.length;
1033
			
1034
			hexLenBytes = ProtoCommon.long2buff(modify_size);
1035
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
1036
			offset += hexLenBytes.length;
1037
			
1038
			OutputStream out = storageSocket.getOutputStream();
1039
			
1040
			System.arraycopy(appenderFilenameBytes, 0, wholePkg, offset, appenderFilenameBytes.length);
1041
			offset += appenderFilenameBytes.length;
1042
			
1043
			out.write(wholePkg);
1044
			if ((this.errno=(byte)callback.send(out)) != 0)
1045
			{
1046
				return this.errno;
1047
			}
1048
			
1049
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1050
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, 0);
1051
			this.errno = pkgInfo.errno;
1052
			if (pkgInfo.errno != 0)
1053
			{
1054
				return this.errno;
1055
			}
1056
						
1057
			return 0;
1058
		}
1059
		catch(IOException ex)
1060
		{
1061
			if (!bNewConnection)
1062
			{
1063
				try
1064
				{
1065
					this.storageServer.close();
1066
				}
1067
				catch(IOException ex1)
1068
				{
1069
					ex1.printStackTrace();
1070
				}
1071
				finally
1072
				{
1073
					this.storageServer = null;
1074
				}
1075
			}
1076
			
1077
			throw ex;
1078
		}
1079
		finally
1080
		{
1081
			if (bNewConnection)
1082
			{
1083
				try
1084
				{
1085
					this.storageServer.close();
1086
				}
1087
				catch(IOException ex1)
1088
				{
1089
					ex1.printStackTrace();
1090
				}
1091
				finally
1092
				{
1093
					this.storageServer = null;
1094
				}
1095
			}
1096
		}
1097
	}
1098
	
1099
	/**
1100
	* delete file from storage server
1101
	* @param group_name the group name of storage server
1102
	*	@param remote_filename filename on storage server
1103
	* @return 0 for success, none zero for fail (error code)
1104
	*/
1105
	public int delete_file(String group_name, String remote_filename) throws IOException, MyException
1106
	{
1107
		boolean bNewConnection = this.newUpdatableStorageConnection(group_name, remote_filename);
1108
		Socket storageSocket = this.storageServer.getSocket();
1109
		
1110
		try
1111
		{
1112
			this.send_package(ProtoCommon.STORAGE_PROTO_CMD_DELETE_FILE, group_name, remote_filename);
1113
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1114
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, 0);
1115
			
1116
			this.errno = pkgInfo.errno;
1117
			return pkgInfo.errno;
1118
		}
1119
		catch(IOException ex)
1120
		{
1121
			if (!bNewConnection)
1122
			{
1123
				try
1124
				{
1125
					this.storageServer.close();
1126
				}
1127
				catch(IOException ex1)
1128
				{
1129
					ex1.printStackTrace();
1130
				}
1131
				finally
1132
				{
1133
					this.storageServer = null;
1134
				}
1135
			}
1136
			
1137
			throw ex;
1138
		}
1139
		finally
1140
		{
1141
			if (bNewConnection)
1142
			{
1143
				try
1144
				{
1145
					this.storageServer.close();
1146
				}
1147
				catch(IOException ex1)
1148
				{
1149
					ex1.printStackTrace();
1150
				}
1151
				finally
1152
				{
1153
					this.storageServer = null;
1154
				}
1155
			}
1156
		}
1157
	}
1158
	
1159
	/**
1160
	* truncate appender file to size 0 from storage server
1161
	* @param group_name the group name of storage server
1162
	*	@param appender_filename the appender filename
1163
	* @return 0 for success, none zero for fail (error code)
1164
	*/
1165
	public int truncate_file(String group_name, String appender_filename) throws IOException, MyException
1166
	{
1167
		final long truncated_file_size = 0;
1168
		return this.truncate_file(group_name, appender_filename, truncated_file_size);
1169
	}
1170
	
1171
	/**
1172
	* truncate appender file from storage server
1173
	* @param group_name the group name of storage server
1174
	*	@param appender_filename the appender filename
1175
	* @param truncated_file_size truncated file size
1176
	* @return 0 for success, none zero for fail (error code)
1177
	*/
1178
	public int truncate_file(String group_name, String appender_filename, 
1179
			long truncated_file_size) throws IOException, MyException
1180
	{
1181
		byte[] header;
1182
		boolean bNewConnection;
1183
		Socket storageSocket;
1184
		byte[] hexLenBytes;
1185
		byte[] appenderFilenameBytes;
1186
		int offset;
1187
		int body_len;
1188
1189
		if ((group_name == null || group_name.length() == 0) || 
1190
		    (appender_filename == null || appender_filename.length() == 0))
1191
		{
1192
			this.errno = ProtoCommon.ERR_NO_EINVAL;
1193
			return this.errno;
1194
		}
1195
		
1196
		bNewConnection = this.newUpdatableStorageConnection(group_name, appender_filename);
1197
		
1198
		try
1199
		{
1200
			storageSocket = this.storageServer.getSocket();
1201
						
1202
			appenderFilenameBytes = appender_filename.getBytes(ClientGlobal.g_charset);
1203
			body_len = 2 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE + appenderFilenameBytes.length;
1204
			
1205
			header = ProtoCommon.packHeader(ProtoCommon.STORAGE_PROTO_CMD_TRUNCATE_FILE, body_len, (byte)0);
1206
			byte[] wholePkg = new byte[header.length + body_len];
1207
			System.arraycopy(header, 0, wholePkg, 0, header.length);
1208
			offset = header.length;
1209
			
1210
			hexLenBytes = ProtoCommon.long2buff(appender_filename.length());
1211
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
1212
			offset += hexLenBytes.length;
1213
			
1214
			hexLenBytes = ProtoCommon.long2buff(truncated_file_size);
1215
			System.arraycopy(hexLenBytes, 0, wholePkg, offset, hexLenBytes.length);
1216
			offset += hexLenBytes.length;
1217
			
1218
			OutputStream out = storageSocket.getOutputStream();
1219
			
1220
			System.arraycopy(appenderFilenameBytes, 0, wholePkg, offset, appenderFilenameBytes.length);
1221
			offset += appenderFilenameBytes.length;
1222
			
1223
			out.write(wholePkg);
1224
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1225
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, 0);
1226
			this.errno = pkgInfo.errno;
1227
			return pkgInfo.errno;
1228
		}
1229
		catch(IOException ex)
1230
		{
1231
			if (!bNewConnection)
1232
			{
1233
				try
1234
				{
1235
					this.storageServer.close();
1236
				}
1237
				catch(IOException ex1)
1238
				{
1239
					ex1.printStackTrace();
1240
				}
1241
				finally
1242
				{
1243
					this.storageServer = null;
1244
				}
1245
			}
1246
			
1247
			throw ex;
1248
		}
1249
		finally
1250
		{
1251
			if (bNewConnection)
1252
			{
1253
				try
1254
				{
1255
					this.storageServer.close();
1256
				}
1257
				catch(IOException ex1)
1258
				{
1259
					ex1.printStackTrace();
1260
				}
1261
				finally
1262
				{
1263
					this.storageServer = null;
1264
				}
1265
			}
1266
		}
1267
	}
1268
	
1269
	/**
1270
	* download file from storage server
1271
	* @param group_name the group name of storage server
1272
	*	@param remote_filename filename on storage server
1273
	* @return file content/buff, return null if fail
1274
	*/
1275
	public byte[] download_file(String group_name, String remote_filename) throws IOException, MyException
1276
	{
1277
		final long file_offset = 0;
1278
		final long download_bytes = 0;
1279
		
1280
		return this.download_file(group_name, remote_filename, file_offset, download_bytes);
1281
	}
1282
	
1283
	/**
1284
	* download file from storage server
1285
	* @param group_name the group name of storage server
1286
	*	@param remote_filename filename on storage server
1287
	* @param file_offset the start offset of the file
1288
	* @param download_bytes download bytes, 0 for remain bytes from offset
1289
	* @return file content/buff, return null if fail
1290
	*/
1291
	public byte[] download_file(String group_name, String remote_filename, long file_offset, long download_bytes) throws IOException, MyException
1292
	{
1293
		boolean bNewConnection = this.newReadableStorageConnection(group_name, remote_filename);
1294
		Socket storageSocket = this.storageServer.getSocket();
1295
		
1296
		try
1297
		{
1298
			ProtoCommon.RecvPackageInfo pkgInfo;
1299
			
1300
			this.send_download_package(group_name, remote_filename, file_offset, download_bytes);
1301
			pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1302
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, -1);
1303
			
1304
			this.errno = pkgInfo.errno;
1305
			if (pkgInfo.errno != 0)
1306
			{
1307
				return null;
1308
			}
1309
			
1310
			return pkgInfo.body;
1311
		}
1312
		catch(IOException ex)
1313
		{
1314
			if (!bNewConnection)
1315
			{
1316
				try
1317
				{
1318
					this.storageServer.close();
1319
				}
1320
				catch(IOException ex1)
1321
				{
1322
					ex1.printStackTrace();
1323
				}
1324
				finally
1325
				{
1326
					this.storageServer = null;
1327
				}
1328
			}
1329
			
1330
			throw ex;
1331
		}
1332
		finally
1333
		{
1334
			if (bNewConnection)
1335
			{
1336
				try
1337
				{
1338
					this.storageServer.close();
1339
				}
1340
				catch(IOException ex1)
1341
				{
1342
					ex1.printStackTrace();
1343
				}
1344
				finally
1345
				{
1346
					this.storageServer = null;
1347
				}
1348
			}
1349
		}
1350
	}
1351
1352
	/**
1353
	* download file from storage server
1354
	* @param group_name the group name of storage server
1355
	*	@param remote_filename filename on storage server
1356
	* @param local_filename  filename on local
1357
	* @return 0 success, return none zero errno if fail
1358
	*/
1359
	public int download_file(String group_name, String remote_filename, 
1360
	                  String local_filename) throws IOException, MyException
1361
	{
1362
		final long file_offset = 0;
1363
		final long download_bytes = 0;
1364
		return this.download_file(group_name, remote_filename, 
1365
	                  file_offset, download_bytes, local_filename);
1366
	}
1367
	
1368
	/**
1369
	* download file from storage server
1370
	* @param group_name the group name of storage server
1371
	*	@param remote_filename filename on storage server
1372
  * @param file_offset the start offset of the file
1373
	* @param download_bytes download bytes, 0 for remain bytes from offset
1374
	* @param local_filename  filename on local
1375
	* @return 0 success, return none zero errno if fail
1376
	*/
1377
	public int download_file(String group_name, String remote_filename, 
1378
	                  long file_offset, long download_bytes, 
1379
	                  String local_filename) throws IOException, MyException
1380
	{
1381
		boolean bNewConnection = this.newReadableStorageConnection(group_name, remote_filename);
1382
		Socket storageSocket = this.storageServer.getSocket();
1383
		try
1384
		{
1385
			ProtoCommon.RecvHeaderInfo header;
1386
			FileOutputStream out = new FileOutputStream(local_filename);
1387
			try
1388
			{
1389
				this.errno = 0;
1390
				this.send_download_package(group_name, remote_filename, file_offset, download_bytes);
1391
				
1392
				InputStream in = storageSocket.getInputStream();
1393
				header = ProtoCommon.recvHeader(in, ProtoCommon.STORAGE_PROTO_CMD_RESP, -1);
1394
				this.errno = header.errno;
1395
				if (header.errno != 0)
1396
				{
1397
					return header.errno;
1398
				}
1399
				
1400
				byte[] buff = new byte[256 * 1024];
1401
				long remainBytes = header.body_len;
1402
				int bytes;
1403
				
1404
				//System.out.println("expect_body_len=" + header.body_len);
1405
				
1406
				while (remainBytes > 0)
1407
				{
1408
					if ((bytes=in.read(buff, 0, remainBytes > buff.length ? buff.length : (int)remainBytes)) < 0)
1409
					{
1410
						throw new IOException("recv package size " + (header.body_len - remainBytes) + " != " + header.body_len);
1411
					}
1412
					
1413
					out.write(buff, 0, bytes);
1414
					remainBytes -= bytes;
1415
					
1416
					//System.out.println("totalBytes=" + (header.body_len - remainBytes));
1417
				}
1418
				
1419
				return 0;
1420
			}
1421
			catch(IOException ex)
1422
			{
1423
				if (this.errno == 0)
1424
				{
1425
					this.errno = ProtoCommon.ERR_NO_EIO;
1426
				}
1427
				
1428
				throw ex;
1429
			}
1430
			finally
1431
			{
1432
				out.close();
1433
				if (this.errno != 0)
1434
				{
1435
					(new File(local_filename)).delete();
1436
				}
1437
			}
1438
		}
1439
		catch(IOException ex)
1440
		{
1441
			if (!bNewConnection)
1442
			{
1443
				try
1444
				{
1445
					this.storageServer.close();
1446
				}
1447
				catch(IOException ex1)
1448
				{
1449
					ex1.printStackTrace();
1450
				}
1451
				finally
1452
				{
1453
					this.storageServer = null;
1454
				}
1455
			}
1456
			
1457
			throw ex;
1458
		}
1459
		finally
1460
		{
1461
			if (bNewConnection)
1462
			{
1463
				try
1464
				{
1465
					this.storageServer.close();
1466
				}
1467
				catch(IOException ex1)
1468
				{
1469
					ex1.printStackTrace();
1470
				}
1471
				finally
1472
				{
1473
					this.storageServer = null;
1474
				}
1475
			}
1476
		}
1477
	}
1478
	
1479
	/**
1480
	* download file from storage server
1481
	* @param group_name the group name of storage server
1482
	*	@param remote_filename filename on storage server
1483
	* @param callback call callback.recv() when data arrive
1484
	* @return 0 success, return none zero errno if fail
1485
	*/
1486
	public int download_file(String group_name, String remote_filename, 
1487
	                  DownloadCallback callback) throws IOException, MyException
1488
	{
1489
		final long file_offset = 0;
1490
		final long download_bytes = 0;
1491
		return this.download_file(group_name, remote_filename, 
1492
	                  file_offset, download_bytes, callback);
1493
	}
1494
	
1495
	/**
1496
	* download file from storage server
1497
	* @param group_name the group name of storage server
1498
	*	@param remote_filename filename on storage server
1499
  * @param file_offset the start offset of the file
1500
	* @param download_bytes download bytes, 0 for remain bytes from offset
1501
	* @param callback call callback.recv() when data arrive
1502
	* @return 0 success, return none zero errno if fail
1503
	*/
1504
	public int download_file(String group_name, String remote_filename, 
1505
	                  long file_offset, long download_bytes, 
1506
	                  DownloadCallback callback) throws IOException, MyException
1507
	{
1508
		int result;
1509
		boolean bNewConnection = this.newReadableStorageConnection(group_name, remote_filename);
1510
		Socket storageSocket = this.storageServer.getSocket();
1511
		
1512
		try
1513
		{
1514
			  ProtoCommon.RecvHeaderInfo header;
1515
				this.send_download_package(group_name, remote_filename, file_offset, download_bytes);
1516
				
1517
				InputStream in = storageSocket.getInputStream();
1518
				header = ProtoCommon.recvHeader(in, ProtoCommon.STORAGE_PROTO_CMD_RESP, -1);
1519
				this.errno = header.errno;
1520
				if (header.errno != 0)
1521
				{
1522
					return header.errno;
1523
				}
1524
				
1525
				byte[] buff = new byte[2 * 1024];
1526
				long remainBytes = header.body_len;
1527
				int bytes;
1528
				
1529
				//System.out.println("expect_body_len=" + header.body_len);
1530
				
1531
				while (remainBytes > 0)
1532
				{
1533
					if ((bytes=in.read(buff, 0, remainBytes > buff.length ? buff.length : (int)remainBytes)) < 0)
1534
					{
1535
						throw new IOException("recv package size " + (header.body_len - remainBytes) + " != " + header.body_len);
1536
					}
1537
					
1538
					if ((result=callback.recv(header.body_len, buff, bytes)) != 0)
1539
					{
1540
						this.errno = (byte)result;
1541
						return result;
1542
					}
1543
					
1544
					remainBytes -= bytes;
1545
					//System.out.println("totalBytes=" + (header.body_len - remainBytes));
1546
				}
1547
				
1548
				return 0;
1549
		}
1550
		catch(IOException ex)
1551
		{
1552
			if (!bNewConnection)
1553
			{
1554
				try
1555
				{
1556
					this.storageServer.close();
1557
				}
1558
				catch(IOException ex1)
1559
				{
1560
					ex1.printStackTrace();
1561
				}
1562
				finally
1563
				{
1564
					this.storageServer = null;
1565
				}
1566
			}
1567
			
1568
			throw ex;
1569
		}
1570
		finally
1571
		{
1572
			if (bNewConnection)
1573
			{
1574
				try
1575
				{
1576
					this.storageServer.close();
1577
				}
1578
				catch(IOException ex1)
1579
				{
1580
					ex1.printStackTrace();
1581
				}
1582
				finally
1583
				{
1584
					this.storageServer = null;
1585
				}
1586
			}
1587
		}
1588
	}
1589
	
1590
	/**
1591
	* get all metadata items from storage server
1592
	* @param group_name the group name of storage server
1593
	*	@param remote_filename filename on storage server
1594
	* @return meta info array, return null if fail
1595
	*/
1596
	public NameValuePair[] get_metadata(String group_name, String remote_filename)throws IOException, MyException
1597
	{
1598
		boolean bNewConnection = this.newUpdatableStorageConnection(group_name, remote_filename);
1599
		Socket storageSocket = this.storageServer.getSocket();
1600
		
1601
		try
1602
		{
1603
			ProtoCommon.RecvPackageInfo pkgInfo;
1604
			
1605
			this.send_package(ProtoCommon.STORAGE_PROTO_CMD_GET_METADATA, group_name, remote_filename);
1606
			pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1607
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, -1);
1608
			
1609
			this.errno = pkgInfo.errno;
1610
			if (pkgInfo.errno != 0)
1611
			{
1612
				return null;
1613
			}
1614
			
1615
			return ProtoCommon.split_metadata(new String(pkgInfo.body, ClientGlobal.g_charset));
1616
		}
1617
		catch(IOException ex)
1618
		{
1619
			if (!bNewConnection)
1620
			{
1621
				try
1622
				{
1623
					this.storageServer.close();
1624
				}
1625
				catch(IOException ex1)
1626
				{
1627
					ex1.printStackTrace();
1628
				}
1629
				finally
1630
				{
1631
					this.storageServer = null;
1632
				}
1633
			}
1634
			
1635
			throw ex;
1636
		}
1637
		finally
1638
		{
1639
			if (bNewConnection)
1640
			{
1641
				try
1642
				{
1643
					this.storageServer.close();
1644
				}
1645
				catch(IOException ex1)
1646
				{
1647
					ex1.printStackTrace();
1648
				}
1649
				finally
1650
				{
1651
					this.storageServer = null;
1652
				}
1653
			}
1654
		}
1655
	}
1656
	
1657
	/**
1658
	* set metadata items to storage server
1659
	* @param group_name the group name of storage server
1660
	*	@param remote_filename filename on storage server
1661
	*	@param meta_list meta item array
1662
	* @param op_flag flag, can be one of following values: <br>
1663
	*            <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_OVERWRITE: overwrite all old
1664
	*				       metadata items</li></ul>
1665
	*            <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_MERGE: merge, insert when
1666
	*				       the metadata item not exist, otherwise update it</li></ul>
1667
	* @return 0 for success, !=0 fail (error code)
1668
	*/
1669
	public int set_metadata(String group_name, String remote_filename,
1670
                            NameValuePair[] meta_list, byte op_flag) throws IOException, MyException
1671
	{
1672
		boolean bNewConnection = this.newUpdatableStorageConnection(group_name, remote_filename);
1673
		Socket storageSocket = this.storageServer.getSocket();
1674
		
1675
		try
1676
		{
1677
			byte[] header;
1678
			byte[] groupBytes;
1679
			byte[] filenameBytes;
1680
			byte[] meta_buff;
1681
			byte[] bs;
1682
			int groupLen;
1683
			byte[] sizeBytes;
1684
			ProtoCommon.RecvPackageInfo pkgInfo;
1685
			
1686
			if (meta_list == null)
1687
			{
1688
				meta_buff = new byte[0];
1689
			}
1690
			else
1691
			{
1692
				meta_buff = ProtoCommon.pack_metadata(meta_list).getBytes(ClientGlobal.g_charset);
1693
			}
1694
			
1695
			filenameBytes = remote_filename.getBytes(ClientGlobal.g_charset);
1696
			sizeBytes = new byte[2 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE];
1697
			Arrays.fill(sizeBytes, (byte)0);
1698
			
1699
			bs = ProtoCommon.long2buff(filenameBytes.length);
1700
			System.arraycopy(bs, 0, sizeBytes, 0, bs.length);
1701
			bs = ProtoCommon.long2buff(meta_buff.length);
1702
			System.arraycopy(bs, 0, sizeBytes, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE, bs.length);
1703
			
1704
			groupBytes = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
1705
			bs = group_name.getBytes(ClientGlobal.g_charset);
1706
			
1707
			Arrays.fill(groupBytes, (byte)0);
1708
			if (bs.length <= groupBytes.length)
1709
			{
1710
				groupLen = bs.length;
1711
			}
1712
			else
1713
			{
1714
				groupLen = groupBytes.length;
1715
			}
1716
			System.arraycopy(bs, 0, groupBytes, 0, groupLen);
1717
			
1718
			header = ProtoCommon.packHeader(ProtoCommon.STORAGE_PROTO_CMD_SET_METADATA, 
1719
			           2 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE + 1 + groupBytes.length
1720
			           + filenameBytes.length + meta_buff.length, (byte)0);
1721
			OutputStream out = storageSocket.getOutputStream();
1722
			byte[] wholePkg = new byte[header.length + sizeBytes.length + 1 + groupBytes.length + filenameBytes.length];
1723
			System.arraycopy(header, 0, wholePkg, 0, header.length);
1724
			System.arraycopy(sizeBytes, 0, wholePkg, header.length, sizeBytes.length);
1725
			wholePkg[header.length+sizeBytes.length] = op_flag;
1726
			System.arraycopy(groupBytes, 0, wholePkg, header.length+sizeBytes.length+1, groupBytes.length);
1727
			System.arraycopy(filenameBytes, 0, wholePkg, header.length+sizeBytes.length+1+groupBytes.length, filenameBytes.length);
1728
			out.write(wholePkg);
1729
			if (meta_buff.length > 0)
1730
			{
1731
		  	out.write(meta_buff);
1732
		  }
1733
		  
1734
			pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1735
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, 0);
1736
			
1737
			this.errno = pkgInfo.errno;
1738
			return pkgInfo.errno;
1739
		}
1740
		catch(IOException ex)
1741
		{
1742
			if (!bNewConnection)
1743
			{
1744
				try
1745
				{
1746
					this.storageServer.close();
1747
				}
1748
				catch(IOException ex1)
1749
				{
1750
					ex1.printStackTrace();
1751
				}
1752
				finally
1753
				{
1754
					this.storageServer = null;
1755
				}
1756
			}
1757
			
1758
			throw ex;
1759
		}
1760
		finally
1761
		{
1762
			if (bNewConnection)
1763
			{
1764
				try
1765
				{
1766
					this.storageServer.close();
1767
				}
1768
				catch(IOException ex1)
1769
				{
1770
					ex1.printStackTrace();
1771
				}
1772
				finally
1773
				{
1774
					this.storageServer = null;
1775
				}
1776
			}
1777
		}
1778
	}
1779
1780
	/**
1781
	* get file info decoded from the filename, fetch from the storage if necessary
1782
	* @param group_name the group name
1783
	*	@param remote_filename the filename
1784
	* @return FileInfo object for success, return null for fail
1785
	*/
1786
	public FileInfo get_file_info(String group_name, String remote_filename) throws IOException, MyException
1787
	{
1788
	  if (remote_filename.length() < ProtoCommon.FDFS_FILE_PATH_LEN + ProtoCommon.FDFS_FILENAME_BASE64_LENGTH
1789
	                   + ProtoCommon.FDFS_FILE_EXT_NAME_MAX_LEN + 1)
1790
	  {
1791
	          this.errno = ProtoCommon.ERR_NO_EINVAL;
1792
	          return null;
1793
	  }
1794
	  
1795
	  byte[] buff = base64.decodeAuto(remote_filename.substring(ProtoCommon.FDFS_FILE_PATH_LEN, 
1796
	  	ProtoCommon.FDFS_FILE_PATH_LEN + ProtoCommon.FDFS_FILENAME_BASE64_LENGTH));
1797
		
1798
	  long file_size = ProtoCommon.buff2long(buff, 4 * 2);
1799
	  if (((remote_filename.length() > ProtoCommon.TRUNK_LOGIC_FILENAME_LENGTH) || 
1800
	          ((remote_filename.length() > ProtoCommon.NORMAL_LOGIC_FILENAME_LENGTH) && ((file_size & ProtoCommon.TRUNK_FILE_MARK_SIZE) == 0))) || 
1801
	          ((file_size & ProtoCommon.APPENDER_FILE_SIZE) != 0))
1802
	  { //slave file or appender file
1803
	  	FileInfo fi = this.query_file_info(group_name, remote_filename);
1804
	  	if (fi == null)
1805
	  	{
1806
	  		return null;
1807
	  	}
1808
	  	return fi;
1809
	  }
1810
	  
1811
		FileInfo fileInfo = new FileInfo(file_size, 0, 0, ProtoCommon.getIpAddress(buff, 0));
1812
    fileInfo.setCreateTimestamp(ProtoCommon.buff2int(buff, 4));
1813
    if ((file_size >> 63) != 0)
1814
    {
1815
	    file_size &= 0xFFFFFFFFL;  //low 32 bits is file size
1816
	    fileInfo.setFileSize(file_size);
1817
    }
1818
    fileInfo.setCrc32(ProtoCommon.buff2int(buff, 4 * 4));
1819
	  
1820
	  return fileInfo;
1821
	}
1822
1823
	/**
1824
	* get file info from storage server
1825
	* @param group_name the group name of storage server
1826
	*	@param remote_filename filename on storage server
1827
	* @return FileInfo object for success, return null for fail
1828
	*/
1829
	public FileInfo query_file_info(String group_name, String remote_filename) throws IOException, MyException
1830
	{
1831
		boolean bNewConnection = this.newUpdatableStorageConnection(group_name, remote_filename);
1832
		Socket storageSocket = this.storageServer.getSocket();
1833
		
1834
		try
1835
		{
1836
			byte[] header;
1837
			byte[] groupBytes;
1838
			byte[] filenameBytes;
1839
			byte[] bs;
1840
			int groupLen;
1841
			ProtoCommon.RecvPackageInfo pkgInfo;
1842
			
1843
			filenameBytes = remote_filename.getBytes(ClientGlobal.g_charset);
1844
			groupBytes = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
1845
			bs = group_name.getBytes(ClientGlobal.g_charset);
1846
			
1847
			Arrays.fill(groupBytes, (byte)0);
1848
			if (bs.length <= groupBytes.length)
1849
			{
1850
				groupLen = bs.length;
1851
			}
1852
			else
1853
			{
1854
				groupLen = groupBytes.length;
1855
			}
1856
			System.arraycopy(bs, 0, groupBytes, 0, groupLen);
1857
			
1858
			header = ProtoCommon.packHeader(ProtoCommon.STORAGE_PROTO_CMD_QUERY_FILE_INFO, 
1859
			           + groupBytes.length + filenameBytes.length, (byte)0);
1860
			OutputStream out = storageSocket.getOutputStream();
1861
			byte[] wholePkg = new byte[header.length + groupBytes.length + filenameBytes.length];
1862
			System.arraycopy(header, 0, wholePkg, 0, header.length);
1863
			System.arraycopy(groupBytes, 0, wholePkg, header.length, groupBytes.length);
1864
			System.arraycopy(filenameBytes, 0, wholePkg, header.length + groupBytes.length, filenameBytes.length);
1865
			out.write(wholePkg);
1866
		  
1867
			pkgInfo = ProtoCommon.recvPackage(storageSocket.getInputStream(), 
1868
	                                     ProtoCommon.STORAGE_PROTO_CMD_RESP, 
1869
	                                     3 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE + 
1870
	                                     ProtoCommon.FDFS_IPADDR_SIZE);
1871
			
1872
			this.errno = pkgInfo.errno;
1873
			if (pkgInfo.errno != 0)
1874
			{
1875
				return null;
1876
			}
1877
			
1878
			long file_size = ProtoCommon.buff2long(pkgInfo.body, 0);
1879
			int create_timestamp = (int)ProtoCommon.buff2long(pkgInfo.body, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
1880
			int crc32 = (int)ProtoCommon.buff2long(pkgInfo.body, 2 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
1881
			String source_ip_addr = (new String(pkgInfo.body, 3 * ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE, ProtoCommon.FDFS_IPADDR_SIZE)).trim();
1882
			return new FileInfo(file_size, create_timestamp, crc32, source_ip_addr);
1883
		}
1884
		catch(IOException ex)
1885
		{
1886
			if (!bNewConnection)
1887
			{
1888
				try
1889
				{
1890
					this.storageServer.close();
1891
				}
1892
				catch(IOException ex1)
1893
				{
1894
					ex1.printStackTrace();
1895
				}
1896
				finally
1897
				{
1898
					this.storageServer = null;
1899
				}
1900
			}
1901
			
1902
			throw ex;
1903
		}
1904
		finally
1905
		{
1906
			if (bNewConnection)
1907
			{
1908
				try
1909
				{
1910
					this.storageServer.close();
1911
				}
1912
				catch(IOException ex1)
1913
				{
1914
					ex1.printStackTrace();
1915
				}
1916
				finally
1917
				{
1918
					this.storageServer = null;
1919
				}
1920
			}
1921
		}
1922
	}
1923
	
1924
	/**
1925
	* check storage socket, if null create a new connection
1926
	* @param group_name the group name to upload file to, can be empty
1927
	* @return true if create a new connection
1928
	*/
1929
	protected boolean newWritableStorageConnection(String group_name) throws IOException, MyException
1930
	{
1931
		if (this.storageServer != null)
1932
		{
1933
			return false;
1934
		}
1935
		else
1936
		{
1937
			TrackerClient tracker = new TrackerClient();
1938
  		this.storageServer = tracker.getStoreStorage(this.trackerServer, group_name);
1939
  		if (this.storageServer == null)
1940
  		{
1941
  			throw new MyException("getStoreStorage fail, errno code: " + tracker.getErrorCode());
1942
  		}
1943
  		return true;
1944
		}
1945
  }
1946
1947
	/**
1948
	* check storage socket, if null create a new connection
1949
	* @param group_name the group name of storage server
1950
	*	@param remote_filename filename on storage server
1951
	* @return true if create a new connection
1952
	*/
1953
	protected boolean newReadableStorageConnection(String group_name, String remote_filename) throws IOException, MyException
1954
	{
1955
		if (this.storageServer != null)
1956
		{
1957
			return false;
1958
		}
1959
		else
1960
		{
1961
			TrackerClient tracker = new TrackerClient();
1962
  		this.storageServer = tracker.getFetchStorage(this.trackerServer, group_name, remote_filename);
1963
  		if (this.storageServer == null)
1964
  		{
1965
  			throw new MyException("getStoreStorage fail, errno code: " + tracker.getErrorCode());
1966
  		}
1967
  		return true;
1968
		}
1969
  }
1970
1971
	/**
1972
	* check storage socket, if null create a new connection
1973
	* @param group_name the group name of storage server
1974
	*	@param remote_filename filename on storage server
1975
	* @return true if create a new connection
1976
	*/
1977
	protected boolean newUpdatableStorageConnection(String group_name, String remote_filename) throws IOException, MyException
1978
	{
1979
		if (this.storageServer != null)
1980
		{
1981
			return false;
1982
		}
1983
		else
1984
		{
1985
			TrackerClient tracker = new TrackerClient();
1986
  		this.storageServer = tracker.getUpdateStorage(this.trackerServer, group_name, remote_filename);
1987
  		if (this.storageServer == null)
1988
  		{
1989
  			throw new MyException("getStoreStorage fail, errno code: " + tracker.getErrorCode());
1990
  		}
1991
  		return true;
1992
		}
1993
  }
1994
  
1995
	/**
1996
	* send package to storage server
1997
	* @param cmd which command to send
1998
	* @param group_name the group name of storage server
1999
	*	@param remote_filename filename on storage server
2000
	*/
2001
	protected void send_package(byte cmd, String group_name, String remote_filename) throws IOException
2002
	{
2003
		byte[] header;
2004
		byte[] groupBytes;
2005
		byte[] filenameBytes;
2006
		byte[] bs;
2007
		int groupLen;
2008
				
2009
		groupBytes = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
2010
		bs = group_name.getBytes(ClientGlobal.g_charset);
2011
		filenameBytes = remote_filename.getBytes(ClientGlobal.g_charset);
2012
		
2013
		Arrays.fill(groupBytes, (byte)0);
2014
		if (bs.length <= groupBytes.length)
2015
		{
2016
			groupLen = bs.length;
2017
		}
2018
		else
2019
		{
2020
			groupLen = groupBytes.length;
2021
		}
2022
		System.arraycopy(bs, 0, groupBytes, 0, groupLen);
2023
		
2024
		header = ProtoCommon.packHeader(cmd, groupBytes.length + filenameBytes.length, (byte)0);
2025
		byte[] wholePkg = new byte[header.length + groupBytes.length + filenameBytes.length];
2026
		System.arraycopy(header, 0, wholePkg, 0, header.length);
2027
		System.arraycopy(groupBytes, 0, wholePkg, header.length, groupBytes.length);
2028
		System.arraycopy(filenameBytes, 0, wholePkg, header.length+groupBytes.length, filenameBytes.length);
2029
		this.storageServer.getSocket().getOutputStream().write(wholePkg);
2030
	}
2031
	
2032
	/**
2033
	* send package to storage server
2034
	* @param group_name the group name of storage server
2035
	*	@param remote_filename filename on storage server
2036
	* @param file_offset the start offset of the file
2037
	* @param download_bytes download bytes
2038
	*/
2039
	protected void send_download_package(String group_name, String remote_filename, long file_offset, long download_bytes) throws IOException
2040
	{
2041
		byte[] header;
2042
		byte[] bsOffset;
2043
		byte[] bsDownBytes;
2044
		byte[] groupBytes;
2045
		byte[] filenameBytes;
2046
		byte[] bs;
2047
		int groupLen;
2048
		
2049
		bsOffset = ProtoCommon.long2buff(file_offset);
2050
		bsDownBytes = ProtoCommon.long2buff(download_bytes);
2051
		groupBytes = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
2052
		bs = group_name.getBytes(ClientGlobal.g_charset);
2053
		filenameBytes = remote_filename.getBytes(ClientGlobal.g_charset);
2054
		
2055
		Arrays.fill(groupBytes, (byte)0);
2056
		if (bs.length <= groupBytes.length)
2057
		{
2058
			groupLen = bs.length;
2059
		}
2060
		else
2061
		{
2062
			groupLen = groupBytes.length;
2063
		}
2064
		System.arraycopy(bs, 0, groupBytes, 0, groupLen);
2065
		
2066
		header = ProtoCommon.packHeader(ProtoCommon.STORAGE_PROTO_CMD_DOWNLOAD_FILE, 
2067
             bsOffset.length + bsDownBytes.length + groupBytes.length + filenameBytes.length, (byte)0);
2068
		byte[] wholePkg = new byte[header.length + bsOffset.length + bsDownBytes.length + groupBytes.length + filenameBytes.length];
2069
		System.arraycopy(header, 0, wholePkg, 0, header.length);
2070
		System.arraycopy(bsOffset, 0, wholePkg, header.length, bsOffset.length);
2071
		System.arraycopy(bsDownBytes, 0, wholePkg, header.length+bsOffset.length, bsDownBytes.length);
2072
		System.arraycopy(groupBytes, 0, wholePkg, header.length+bsOffset.length+bsDownBytes.length, groupBytes.length);
2073
		System.arraycopy(filenameBytes, 0, wholePkg, header.length+bsOffset.length+bsDownBytes.length+groupBytes.length, filenameBytes.length);
2074
		this.storageServer.getSocket().getOutputStream().write(wholePkg);
2075
	}
2076
}

+ 799 - 0
src/main/java/org/csource/fastdfs/StorageClient1.java

@ -0,0 +1,799 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import org.csource.common.MyException;
12
import org.csource.common.NameValuePair;
13
14
import java.io.IOException;
15
16
/**
17
* Storage client for 1 field file id: combined group name and filename
18
* @author Happy Fish / YuQing
19
* @version Version 1.21
20
*/
21
public class StorageClient1 extends StorageClient
22
{
23
	public static final String SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR = "/";
24
	
25
/**
26
* constructor
27
*/
28
	public StorageClient1()
29
	{
30
		super();
31
	}
32
	
33
/**
34
* constructor
35
* @param trackerServer the tracker server, can be null
36
* @param storageServer the storage server, can be null
37
*/
38
	public StorageClient1(TrackerServer trackerServer, StorageServer storageServer)
39
	{
40
		super(trackerServer, storageServer);
41
	}
42
43
	public static byte split_file_id(String file_id, String[] results)
44
	{
45
		int pos = file_id.indexOf(SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR);
46
		if ((pos <= 0) || (pos == file_id.length() - 1))
47
		{
48
			return ProtoCommon.ERR_NO_EINVAL;
49
		}
50
		
51
		results[0] = file_id.substring(0, pos); //group name
52
		results[1] = file_id.substring(pos + 1); //file name
53
		return 0;
54
  }
55
  	
56
	/**
57
	* upload file to storage server (by file name)
58
	* @param local_filename local filename to upload
59
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
60
	* @param meta_list meta info array
61
	* @return  file id(including group name and filename) if success, <br>
62
	*         return null if fail
63
	*/
64
	public String upload_file1(String local_filename, String file_ext_name, 
65
	       NameValuePair[] meta_list) throws IOException, MyException
66
	{
67
		String parts[] = this.upload_file(local_filename, file_ext_name, meta_list);
68
		if (parts != null)
69
		{
70
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
71
		}
72
		else
73
		{
74
			return null;
75
		}
76
	}
77
78
	/**
79
	* upload file to storage server (by file name)
80
	* @param group_name the group name to upload file to, can be empty
81
	* @param local_filename local filename to upload
82
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
83
	* @param meta_list meta info array
84
	* @return  file id(including group name and filename) if success, <br>
85
	*         return null if fail
86
	*/
87
	public String upload_file1(String group_name, String local_filename, String file_ext_name, 
88
	       NameValuePair[] meta_list) throws IOException, MyException
89
	{
90
		String parts[] = this.upload_file(group_name, local_filename, file_ext_name, meta_list);
91
		if (parts != null)
92
		{
93
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
94
		}
95
		else
96
		{
97
			return null;
98
		}
99
	}
100
	
101
	/**
102
	* upload file to storage server (by file buff)
103
	* @param file_buff file content/buff
104
	* @param file_ext_name file ext name, do not include dot(.)
105
	*	@param meta_list meta info array
106
	* @return  file id(including group name and filename) if success, <br>
107
	*         return null if fail
108
	*/
109
	public String upload_file1(byte[] file_buff, String file_ext_name,	
110
	       NameValuePair[] meta_list) throws IOException, MyException
111
	{
112
		String parts[] = this.upload_file(file_buff, file_ext_name, meta_list);
113
		if (parts != null)
114
		{
115
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
116
		}
117
		else
118
		{
119
			return null;
120
		}
121
	}
122
123
	/**
124
	* upload file to storage server (by file buff)
125
	* @param group_name the group name to upload file to, can be empty
126
	* @param file_buff file content/buff
127
	* @param file_ext_name file ext name, do not include dot(.)
128
	*	@param meta_list meta info array
129
	* @return  file id(including group name and filename) if success, <br>
130
	*         return null if fail
131
	*/
132
	public String upload_file1(String group_name, byte[] file_buff, String file_ext_name,	
133
	       NameValuePair[] meta_list) throws IOException, MyException
134
	{
135
		String parts[] = this.upload_file(group_name, file_buff, file_ext_name, meta_list);
136
		if (parts != null)
137
		{
138
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
139
		}
140
		else
141
		{
142
			return null;
143
		}
144
	}
145
146
	/**
147
	* upload file to storage server (by callback)
148
	* @param group_name the group name to upload file to, can be empty
149
	* @param file_size the file size
150
	* @param callback the write data callback object
151
	* @param file_ext_name file ext name, do not include dot(.)
152
	*	@param meta_list meta info array
153
  * @return file id(including group name and filename) if success, <br>
154
	*         return null if fail
155
	*/
156
	public String upload_file1(String group_name, long file_size, 
157
	       UploadCallback callback, String file_ext_name, 
158
	       NameValuePair[] meta_list) throws IOException, MyException
159
	{
160
		String parts[] = this.upload_file(group_name, file_size, callback, file_ext_name, meta_list);
161
		if (parts != null)
162
		{
163
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
164
		}
165
		else
166
		{
167
			return null;
168
		}
169
	}
170
171
	/**
172
	* upload appender file to storage server (by file name)
173
	* @param local_filename local filename to upload
174
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
175
	* @param meta_list meta info array
176
	* @return  file id(including group name and filename) if success, <br>
177
	*         return null if fail
178
	*/
179
	public String upload_appender_file1(String local_filename, String file_ext_name, 
180
	       NameValuePair[] meta_list) throws IOException, MyException
181
	{
182
		String parts[] = this.upload_appender_file(local_filename, file_ext_name, meta_list);
183
		if (parts != null)
184
		{
185
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
186
		}
187
		else
188
		{
189
			return null;
190
		}
191
	}
192
193
	/**
194
	* upload appender file to storage server (by file name)
195
	* @param group_name the group name to upload file to, can be empty
196
	* @param local_filename local filename to upload
197
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
198
	* @param meta_list meta info array
199
	* @return  file id(including group name and filename) if success, <br>
200
	*         return null if fail
201
	*/
202
	public String upload_appender_file1(String group_name, String local_filename, String file_ext_name, 
203
	       NameValuePair[] meta_list) throws IOException, MyException
204
	{
205
		String parts[] = this.upload_appender_file(group_name, local_filename, file_ext_name, meta_list);
206
		if (parts != null)
207
		{
208
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
209
		}
210
		else
211
		{
212
			return null;
213
		}
214
	}
215
	
216
	/**
217
	* upload appender file to storage server (by file buff)
218
	* @param file_buff file content/buff
219
	* @param file_ext_name file ext name, do not include dot(.)
220
	*	@param meta_list meta info array
221
	* @return  file id(including group name and filename) if success, <br>
222
	*         return null if fail
223
	*/
224
	public String upload_appender_file1(byte[] file_buff, String file_ext_name,	
225
	       NameValuePair[] meta_list) throws IOException, MyException
226
	{
227
		String parts[] = this.upload_appender_file(file_buff, file_ext_name, meta_list);
228
		if (parts != null)
229
		{
230
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
231
		}
232
		else
233
		{
234
			return null;
235
		}
236
	}
237
238
	/**
239
	* upload appender file to storage server (by file buff)
240
	* @param group_name the group name to upload file to, can be empty
241
	* @param file_buff file content/buff
242
	* @param file_ext_name file ext name, do not include dot(.)
243
	*	@param meta_list meta info array
244
	* @return  file id(including group name and filename) if success, <br>
245
	*         return null if fail
246
	*/
247
	public String upload_appender_file1(String group_name, byte[] file_buff, String file_ext_name,	
248
	       NameValuePair[] meta_list) throws IOException, MyException
249
	{
250
		String parts[] = this.upload_appender_file(group_name, file_buff, file_ext_name, meta_list);
251
		if (parts != null)
252
		{
253
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
254
		}
255
		else
256
		{
257
			return null;
258
		}
259
	}
260
261
	/**
262
	* upload appender file to storage server (by callback)
263
	* @param group_name the group name to upload file to, can be empty
264
	* @param file_size the file size
265
	* @param callback the write data callback object
266
	* @param file_ext_name file ext name, do not include dot(.)
267
	*	@param meta_list meta info array
268
  * @return file id(including group name and filename) if success, <br>
269
	*         return null if fail
270
	*/
271
	public String upload_appender_file1(String group_name, long file_size, 
272
	       UploadCallback callback, String file_ext_name, 
273
	       NameValuePair[] meta_list) throws IOException, MyException
274
	{
275
		String parts[] = this.upload_appender_file(group_name, file_size, callback, file_ext_name, meta_list);
276
		if (parts != null)
277
		{
278
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
279
		}
280
		else
281
		{
282
			return null;
283
		}
284
	}
285
	
286
	/**
287
	* upload file to storage server (by file name, slave file mode)
288
	* @param master_file_id the master file id to generate the slave file
289
	* @param prefix_name the prefix name to generate the slave file
290
	* @param local_filename local filename to upload
291
	* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
292
	* @param meta_list meta info array
293
	* @return  file id(including group name and filename) if success, <br>
294
	*         return null if fail
295
	*/
296
	public String upload_file1(String master_file_id, String prefix_name, 
297
	       String local_filename, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
298
	{
299
		String[] parts = new String[2];
300
		this.errno = this.split_file_id(master_file_id, parts);
301
		if (this.errno != 0)
302
		{
303
			return null;
304
		}
305
		
306
		parts = this.upload_file(parts[0], parts[1], prefix_name, 
307
		                                  local_filename,	file_ext_name, meta_list);
308
		if (parts != null)
309
		{
310
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
311
		}
312
		else
313
		{
314
			return null;
315
		}
316
	}
317
	
318
	/**
319
	* upload file to storage server (by file buff, slave file mode)
320
	* @param master_file_id the master file id to generate the slave file
321
	* @param prefix_name the prefix name to generate the slave file
322
	* @param file_buff file content/buff
323
	* @param file_ext_name file ext name, do not include dot(.)
324
	*	@param meta_list meta info array
325
	* @return  file id(including group name and filename) if success, <br>
326
	*         return null if fail
327
	*/
328
	public String upload_file1(String master_file_id, String prefix_name, 
329
	       byte[] file_buff, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException
330
	{
331
		String[] parts = new String[2];
332
		this.errno = this.split_file_id(master_file_id, parts);
333
		if (this.errno != 0)
334
		{
335
			return null;
336
		}
337
		
338
		parts = this.upload_file(parts[0], parts[1], prefix_name, file_buff, file_ext_name, meta_list);
339
		if (parts != null)
340
		{
341
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
342
		}
343
		else
344
		{
345
			return null;
346
		}
347
	}
348
349
	/**
350
	* upload file to storage server (by file buff, slave file mode)
351
	* @param master_file_id the master file id to generate the slave file
352
	* @param prefix_name the prefix name to generate the slave file
353
	* @param file_buff file content/buff
354
	* @param file_ext_name file ext name, do not include dot(.)
355
	*	@param meta_list meta info array
356
	* @return  file id(including group name and filename) if success, <br>
357
	*         return null if fail
358
	*/
359
	public String upload_file1(String master_file_id, String prefix_name, 
360
	       byte[] file_buff, int offset, int length, String file_ext_name, 
361
	       NameValuePair[] meta_list) throws IOException, MyException
362
	{
363
		String[] parts = new String[2];
364
		this.errno = this.split_file_id(master_file_id, parts);
365
		if (this.errno != 0)
366
		{
367
			return null;
368
		}
369
		
370
		parts = this.upload_file(parts[0], parts[1], prefix_name, file_buff, 
371
		             offset, length, file_ext_name, meta_list);
372
		if (parts != null)
373
		{
374
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
375
		}
376
		else
377
		{
378
			return null;
379
		}
380
	}
381
	
382
	/**
383
	* upload file to storage server (by callback)
384
	* @param master_file_id the master file id to generate the slave file
385
	* @param prefix_name the prefix name to generate the slave file
386
	* @param file_size the file size
387
	* @param callback the write data callback object
388
	* @param file_ext_name file ext name, do not include dot(.)
389
	*	@param meta_list meta info array
390
  * @return file id(including group name and filename) if success, <br>
391
	*         return null if fail
392
	*/
393
	public String upload_file1(String master_file_id, String prefix_name, long file_size, 
394
	       UploadCallback callback, String file_ext_name, 
395
	       NameValuePair[] meta_list) throws IOException, MyException
396
	{
397
		String[] parts = new String[2];
398
		this.errno = this.split_file_id(master_file_id, parts);
399
		if (this.errno != 0)
400
		{
401
			return null;
402
		}
403
		
404
		parts = this.upload_file(parts[0], parts[1], prefix_name, file_size, callback, file_ext_name, meta_list);
405
		if (parts != null)
406
		{
407
			return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
408
		}
409
		else
410
		{
411
			return null;
412
		}
413
	}
414
415
	/**
416
	* append file to storage server (by file name)
417
	* @param appender_file_id the appender file id
418
	* @param local_filename local filename to append
419
	* @return 0 for success, != 0 for error (error no)
420
	*/
421
	public int append_file1(String appender_file_id, String local_filename) throws IOException, MyException
422
	{
423
		String[] parts = new String[2];
424
		this.errno = this.split_file_id(appender_file_id, parts);
425
		if (this.errno != 0)
426
		{
427
			return this.errno;
428
		}
429
		
430
		return this.append_file(parts[0], parts[1], local_filename);
431
	}
432
	
433
	/**
434
	* append file to storage server (by file buff)
435
	* @param appender_file_id the appender file id
436
	* @param file_buff file content/buff
437
	* @return 0 for success, != 0 for error (error no)
438
	*/
439
	public int append_file1(String appender_file_id, byte[] file_buff) throws IOException, MyException
440
	{
441
		String[] parts = new String[2];
442
		this.errno = this.split_file_id(appender_file_id, parts);
443
		if (this.errno != 0)
444
		{
445
			return this.errno;
446
		}
447
		
448
		return this.append_file(parts[0], parts[1], file_buff);
449
	}
450
	
451
	/**
452
	* append file to storage server (by file buff)
453
	* @param appender_file_id the appender file id
454
	* @param file_buff file content/buffer
455
	* @param offset start offset of the buffer
456
	* @param length the length of the buffer to append
457
	* @return 0 for success, != 0 for error (error no)
458
	*/
459
	public int append_file1(String appender_file_id, byte[] file_buff, int offset, int length) throws IOException, MyException
460
	{
461
		String[] parts = new String[2];
462
		this.errno = this.split_file_id(appender_file_id, parts);
463
		if (this.errno != 0)
464
		{
465
			return this.errno;
466
		}
467
		
468
		return this.append_file(parts[0], parts[1], file_buff, offset, length);
469
	}
470
471
	/**
472
	* append file to storage server (by callback)
473
	* @param appender_file_id the appender file id
474
	* @param file_size the file size
475
	* @param callback the write data callback object
476
	* @return 0 for success, != 0 for error (error no)
477
	*/
478
	public int append_file1(String appender_file_id, long file_size, UploadCallback callback) throws IOException, MyException
479
	{
480
		String[] parts = new String[2];
481
		this.errno = this.split_file_id(appender_file_id, parts);
482
		if (this.errno != 0)
483
		{
484
			return this.errno;
485
		}
486
		
487
		return this.append_file(parts[0], parts[1], file_size, callback);
488
	}
489
	
490
	/**
491
	* modify appender file to storage server (by file name)
492
	* @param appender_file_id the appender file id
493
	* @param file_offset the offset of appender file
494
	* @param local_filename local filename to append
495
	* @return 0 for success, != 0 for error (error no)
496
	*/
497
	public int modify_file1(String appender_file_id, 
498
			long file_offset, String local_filename) throws IOException, MyException
499
	{
500
		String[] parts = new String[2];
501
		this.errno = this.split_file_id(appender_file_id, parts);
502
		if (this.errno != 0)
503
		{
504
			return this.errno;
505
		}
506
		
507
		return this.modify_file(parts[0], parts[1], file_offset, local_filename);
508
	}
509
	
510
	/**
511
	* modify appender file to storage server (by file buff)
512
	* @param appender_file_id the appender file id
513
	* @param file_offset the offset of appender file
514
	* @param file_buff file content/buff
515
	* @return 0 for success, != 0 for error (error no)
516
	*/
517
	public int modify_file1(String appender_file_id, 
518
			long file_offset, byte[] file_buff) throws IOException, MyException
519
	{
520
		String[] parts = new String[2];
521
		this.errno = this.split_file_id(appender_file_id, parts);
522
		if (this.errno != 0)
523
		{
524
			return this.errno;
525
		}
526
		
527
		return this.modify_file(parts[0], parts[1], file_offset, file_buff);
528
	}
529
	
530
	/**
531
	* modify appender file to storage server (by file buff)
532
	* @param appender_file_id the appender file id
533
	* @param file_offset the offset of appender file
534
	* @param file_buff file content/buff
535
	* @param buffer_offset start offset of the buff
536
	* @param buffer_length the length of buff to modify
537
	* @return 0 for success, != 0 for error (error no)
538
	*/
539
	public int modify_file1(String appender_file_id, 
540
	       long file_offset, byte[] file_buff, int buffer_offset, int buffer_length) throws IOException, MyException
541
	{
542
		String[] parts = new String[2];
543
		this.errno = this.split_file_id(appender_file_id, parts);
544
		if (this.errno != 0)
545
		{
546
			return this.errno;
547
		}
548
		
549
		return this.modify_file(parts[0], parts[1], file_offset, 
550
				file_buff, buffer_offset, buffer_length);
551
	}
552
	
553
	/**
554
	* modify appender file to storage server (by callback)
555
	* @param appender_file_id the appender file id
556
	* @param file_offset the offset of appender file
557
	* @param modify_size the modify size
558
	* @param callback the write data callback object
559
	* @return 0 for success, != 0 for error (error no)
560
	*/
561
	public int modify_file1(String appender_file_id, 
562
	       long file_offset, long modify_size, UploadCallback callback) throws IOException, MyException
563
	{
564
		String[] parts = new String[2];
565
		this.errno = this.split_file_id(appender_file_id, parts);
566
		if (this.errno != 0)
567
		{
568
			return this.errno;
569
		}
570
		
571
		return this.modify_file(parts[0], parts[1], file_offset, modify_size, callback);
572
	}
573
	
574
	/**
575
	* delete file from storage server
576
	* @param file_id the file id(including group name and filename)
577
	* @return 0 for success, none zero for fail (error code)
578
	*/
579
	public int delete_file1(String file_id) throws IOException, MyException
580
	{
581
		String[] parts = new String[2];
582
		this.errno = this.split_file_id(file_id, parts);
583
		if (this.errno != 0)
584
		{
585
			return this.errno;
586
		}
587
		
588
		return this.delete_file(parts[0], parts[1]);
589
	}
590
591
	/**
592
	* truncate appender file to size 0 from storage server
593
  * @param appender_file_id the appender file id
594
	* @return 0 for success, none zero for fail (error code)
595
	*/
596
	public int truncate_file1(String appender_file_id) throws IOException, MyException
597
	{
598
		String[] parts = new String[2];
599
		this.errno = this.split_file_id(appender_file_id, parts);
600
		if (this.errno != 0)
601
		{
602
			return this.errno;
603
		}
604
		
605
		return this.truncate_file(parts[0], parts[1]);
606
	}
607
	
608
	/**
609
	* truncate appender file from storage server
610
  * @param appender_file_id the appender file id
611
	* @param truncated_file_size truncated file size
612
	* @return 0 for success, none zero for fail (error code)
613
	*/
614
	public int truncate_file1(String appender_file_id, long truncated_file_size) throws IOException, MyException
615
	{
616
		String[] parts = new String[2];
617
		this.errno = this.split_file_id(appender_file_id, parts);
618
		if (this.errno != 0)
619
		{
620
			return this.errno;
621
		}
622
		
623
		return this.truncate_file(parts[0], parts[1], truncated_file_size);
624
	}
625
	
626
	/**
627
	* download file from storage server
628
	* @param file_id the file id(including group name and filename)
629
	* @return file content/buffer, return null if fail
630
	*/
631
	public byte[] download_file1(String file_id) throws IOException, MyException
632
	{
633
		final long file_offset = 0;
634
		final long download_bytes = 0;
635
		
636
		return this.download_file1(file_id, file_offset, download_bytes);
637
	}
638
	
639
	/**
640
	* download file from storage server
641
	* @param file_id the file id(including group name and filename)
642
	* @param file_offset the start offset of the file
643
	* @param download_bytes download bytes, 0 for remain bytes from offset
644
	* @return file content/buff, return null if fail
645
	*/
646
	public byte[] download_file1(String file_id, long file_offset, long download_bytes) throws IOException, MyException
647
	{
648
		String[] parts = new String[2];
649
		this.errno = this.split_file_id(file_id, parts);
650
		if (this.errno != 0)
651
		{
652
			return null;
653
		}
654
		
655
		return this.download_file(parts[0], parts[1], file_offset, download_bytes);
656
	}
657
658
	/**
659
	* download file from storage server
660
	* @param file_id the file id(including group name and filename)
661
	* @param local_filename  the filename on local
662
	* @return 0 success, return none zero errno if fail
663
	*/
664
	public int download_file1(String file_id, String local_filename) throws IOException, MyException
665
	{
666
		final long file_offset = 0;
667
		final long download_bytes = 0;
668
		
669
		return this.download_file1(file_id, file_offset, download_bytes, local_filename);
670
	}
671
	
672
	/**
673
	* download file from storage server
674
	* @param file_id the file id(including group name and filename)
675
	* @param file_offset the start offset of the file
676
	* @param download_bytes download bytes, 0 for remain bytes from offset
677
	* @param local_filename  the filename on local
678
	* @return 0 success, return none zero errno if fail
679
	*/
680
	public int download_file1(String file_id, long file_offset, long download_bytes, String local_filename) throws IOException, MyException
681
	{
682
		String[] parts = new String[2];
683
		this.errno = this.split_file_id(file_id, parts);
684
		if (this.errno != 0)
685
		{
686
			return this.errno;
687
		}
688
		
689
		return this.download_file(parts[0], parts[1], file_offset, download_bytes, local_filename);
690
	}
691
	
692
	/**
693
	* download file from storage server
694
	* @param file_id the file id(including group name and filename)
695
	* @param callback the callback object, will call callback.recv() when data arrive
696
	* @return 0 success, return none zero errno if fail
697
	*/
698
	public int download_file1(String file_id, DownloadCallback callback) throws IOException, MyException
699
	{
700
		final long file_offset = 0;
701
		final long download_bytes = 0;
702
		
703
		return this.download_file1(file_id, file_offset, download_bytes, callback);
704
	}
705
	
706
	/**
707
	* download file from storage server
708
	* @param file_id the file id(including group name and filename)
709
	* @param file_offset the start offset of the file
710
	* @param download_bytes download bytes, 0 for remain bytes from offset
711
	* @param callback the callback object, will call callback.recv() when data arrive
712
	* @return 0 success, return none zero errno if fail
713
	*/
714
	public int download_file1(String file_id, long file_offset, long download_bytes, DownloadCallback callback) throws IOException, MyException
715
	{
716
		String[] parts = new String[2];
717
		this.errno = this.split_file_id(file_id, parts);
718
		if (this.errno != 0)
719
		{
720
			return this.errno;
721
		}
722
		
723
		return this.download_file(parts[0], parts[1], file_offset, download_bytes, callback);
724
	}
725
726
	/**
727
	* get all metadata items from storage server
728
	* @param file_id the file id(including group name and filename)
729
	* @return meta info array, return null if fail
730
	*/
731
	public NameValuePair[] get_metadata1(String file_id)throws IOException, MyException
732
	{
733
		String[] parts = new String[2];
734
		this.errno = this.split_file_id(file_id, parts);
735
		if (this.errno != 0)
736
		{
737
			return null;
738
		}
739
		
740
		return this.get_metadata(parts[0], parts[1]);
741
	}
742
	
743
	/**
744
	* set metadata items to storage server
745
	* @param file_id the file id(including group name and filename)
746
	*	@param meta_list meta item array
747
	* @param op_flag flag, can be one of following values: <br>
748
	*            <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_OVERWRITE: overwrite all old
749
	*				       metadata items</li></ul>
750
	*            <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_MERGE: merge, insert when
751
	*				       the metadata item not exist, otherwise update it</li></ul>
752
	* @return 0 for success, !=0 fail (error code)
753
	*/
754
	public int set_metadata1(String file_id, NameValuePair[] meta_list, byte op_flag) throws IOException, MyException
755
	{
756
		String[] parts = new String[2];
757
		this.errno = this.split_file_id(file_id, parts);
758
		if (this.errno != 0)
759
		{
760
			return this.errno;
761
		}
762
		
763
		return this.set_metadata(parts[0], parts[1], meta_list, op_flag);
764
	}
765
	
766
	/**
767
	* get file info from storage server
768
	* @param file_id the file id(including group name and filename)
769
	* @return FileInfo object for success, return null for fail
770
	*/
771
	public FileInfo query_file_info1(String file_id) throws IOException, MyException
772
	{
773
		String[] parts = new String[2];
774
		this.errno = this.split_file_id(file_id, parts);
775
		if (this.errno != 0)
776
		{
777
			return null;
778
		}
779
		
780
		return this.query_file_info(parts[0], parts[1]);
781
	}
782
	
783
	/**
784
	* get file info decoded from filename
785
	* @param file_id the file id(including group name and filename)
786
	* @return FileInfo object for success, return null for fail
787
	*/
788
	public FileInfo get_file_info1(String file_id) throws IOException, MyException
789
	{
790
		String[] parts = new String[2];
791
		this.errno = this.split_file_id(file_id, parts);
792
		if (this.errno != 0)
793
		{
794
			return null;
795
		}
796
		
797
		return this.get_file_info(parts[0], parts[1]);
798
	}
799
}

+ 61 - 0
src/main/java/org/csource/fastdfs/StorageServer.java

@ -0,0 +1,61 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.net.InetSocketAddress;
13
14
/**
15
* Storage Server Info
16
* @author Happy Fish / YuQing
17
* @version Version 1.11
18
*/
19
public class StorageServer extends TrackerServer
20
{
21
	protected int store_path_index = 0;
22
	
23
/**
24
* Constructor
25
* @param ip_addr the ip address of storage server
26
* @param port the port of storage server
27
* @param store_path the store path index on the storage server
28
*/
29
	public StorageServer(String ip_addr, int port, int store_path) throws IOException
30
	{		
31
		super(ClientGlobal.getSocket(ip_addr, port), new InetSocketAddress(ip_addr, port));
32
		this.store_path_index = store_path;
33
	}
34
35
/**
36
* Constructor
37
* @param ip_addr the ip address of storage server
38
* @param port the port of storage server
39
* @param store_path the store path index on the storage server
40
*/
41
	public StorageServer(String ip_addr, int port, byte store_path) throws IOException
42
	{
43
		super(ClientGlobal.getSocket(ip_addr, port), new InetSocketAddress(ip_addr, port));
44
		if (store_path < 0)
45
		{
46
			this.store_path_index = 256 + store_path;
47
		}
48
		else
49
		{
50
			this.store_path_index = store_path;
51
		}
52
	}
53
	
54
/**
55
* @return the store path index on the storage server
56
*/
57
	public int getStorePathIndex()
58
	{
59
		return this.store_path_index;
60
	}
61
}

+ 79 - 0
src/main/java/org/csource/fastdfs/StructBase.java

@ -0,0 +1,79 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.UnsupportedEncodingException;
12
import java.util.Date;
13
14
/**
15
* C struct body decoder
16
* @author Happy Fish / YuQing
17
* @version Version 1.17
18
*/
19
public abstract class StructBase
20
{
21
	protected static class FieldInfo
22
	{
23
		protected String name;
24
		protected int offset;
25
		protected int size;
26
		
27
		public FieldInfo(String name, int offset, int size)
28
		{
29
			this.name = name;
30
			this.offset = offset;
31
			this.size = size;
32
		}
33
	}
34
	
35
/**
36
* set fields
37
* @param bs byte array
38
* @param offset start offset
39
*/
40
	public abstract void setFields(byte[] bs, int offset);
41
	
42
	protected String stringValue(byte[] bs, int offset, FieldInfo filedInfo)
43
	{
44
		try
45
		{
46
			return (new String(bs, offset + filedInfo.offset, filedInfo.size, ClientGlobal.g_charset)).trim();
47
		}
48
		catch(UnsupportedEncodingException ex)
49
		{
50
			ex.printStackTrace();
51
			return null;
52
		}
53
	}
54
	
55
	protected long longValue(byte[] bs, int offset, FieldInfo filedInfo)
56
	{
57
		return ProtoCommon.buff2long(bs, offset + filedInfo.offset);
58
	}
59
	
60
	protected int intValue(byte[] bs, int offset, FieldInfo filedInfo)
61
	{
62
		return (int) ProtoCommon.buff2long(bs, offset + filedInfo.offset);
63
	}
64
	
65
	protected byte byteValue(byte[] bs, int offset, FieldInfo filedInfo)
66
	{
67
		return bs[offset + filedInfo.offset];
68
	}
69
70
	protected boolean booleanValue(byte[] bs, int offset, FieldInfo filedInfo)
71
	{
72
		return bs[offset + filedInfo.offset] != 0;
73
	}
74
	
75
	protected Date dateValue(byte[] bs, int offset, FieldInfo filedInfo)
76
	{
77
		return new Date(ProtoCommon.buff2long(bs, offset + filedInfo.offset) * 1000);
78
	}
79
}

+ 226 - 0
src/main/java/org/csource/fastdfs/StructGroupStat.java

@ -0,0 +1,226 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
/**
12
* C struct body decoder
13
* @author Happy Fish / YuQing
14
* @version Version 1.18
15
*/
16
public class StructGroupStat extends StructBase
17
{
18
	protected static final int FIELD_INDEX_GROUP_NAME            = 0;
19
	protected static final int FIELD_INDEX_TOTAL_MB              = 1;
20
	protected static final int FIELD_INDEX_FREE_MB               = 2;
21
	protected static final int FIELD_INDEX_TRUNK_FREE_MB         = 3;
22
	protected static final int FIELD_INDEX_STORAGE_COUNT         = 4;
23
	protected static final int FIELD_INDEX_STORAGE_PORT          = 5;
24
	protected static final int FIELD_INDEX_STORAGE_HTTP_PORT     = 6;
25
	protected static final int FIELD_INDEX_ACTIVE_COUNT          = 7;
26
	protected static final int FIELD_INDEX_CURRENT_WRITE_SERVER  = 8;
27
	protected static final int FIELD_INDEX_STORE_PATH_COUNT      = 9;
28
	protected static final int FIELD_INDEX_SUBDIR_COUNT_PER_PATH = 10;
29
	protected static final int FIELD_INDEX_CURRENT_TRUNK_FILE_ID = 11;
30
	
31
	protected static int fieldsTotalSize;
32
	protected static StructBase.FieldInfo[] fieldsArray = new StructBase.FieldInfo[12];
33
	
34
	static
35
	{
36
		int offset = 0;
37
		fieldsArray[FIELD_INDEX_GROUP_NAME] = new StructBase.FieldInfo("groupName", offset, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1);
38
		offset += ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1;
39
		
40
		fieldsArray[FIELD_INDEX_TOTAL_MB] = new StructBase.FieldInfo("totalMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
41
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
42
		
43
		fieldsArray[FIELD_INDEX_FREE_MB] = new StructBase.FieldInfo("freeMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
44
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
45
		
46
		fieldsArray[FIELD_INDEX_TRUNK_FREE_MB] = new StructBase.FieldInfo("trunkFreeMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
47
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
48
49
		fieldsArray[FIELD_INDEX_STORAGE_COUNT] = new StructBase.FieldInfo("storageCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
50
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
51
		
52
		fieldsArray[FIELD_INDEX_STORAGE_PORT] = new StructBase.FieldInfo("storagePort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
53
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
54
		
55
		fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT] = new StructBase.FieldInfo("storageHttpPort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
56
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
57
		
58
		fieldsArray[FIELD_INDEX_ACTIVE_COUNT] = new StructBase.FieldInfo("activeCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
59
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
60
		
61
		fieldsArray[FIELD_INDEX_CURRENT_WRITE_SERVER] = new StructBase.FieldInfo("currentWriteServer", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
62
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
63
		
64
		fieldsArray[FIELD_INDEX_STORE_PATH_COUNT] = new StructBase.FieldInfo("storePathCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
65
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
66
		
67
		fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH] = new StructBase.FieldInfo("subdirCountPerPath", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
68
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
69
70
		fieldsArray[FIELD_INDEX_CURRENT_TRUNK_FILE_ID] = new StructBase.FieldInfo("currentTrunkFileId", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
71
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
72
				
73
		fieldsTotalSize = offset;
74
	}
75
	
76
	protected String groupName;  //name of this group
77
	protected long totalMB;      //total disk storage in MB
78
	protected long freeMB;       //free disk space in MB
79
	protected long trunkFreeMB;  //trunk free space in MB
80
	protected int storageCount;  //storage server count
81
  protected int storagePort;   //storage server port
82
  protected int storageHttpPort; //storage server HTTP port
83
  protected int activeCount;     //active storage server count
84
  protected int currentWriteServer; //current storage server index to upload file
85
  protected int storePathCount;     //store base path count of each storage server
86
  protected int subdirCountPerPath; //sub dir count per store path
87
	protected int currentTrunkFileId; //current trunk file id
88
	
89
/**
90
* get group name
91
* @return group name
92
*/
93
  public String getGroupName()
94
  {
95
  	return this.groupName;
96
  }
97
98
/**
99
* get total disk space in MB
100
* @return total disk space in MB
101
*/
102
  public long getTotalMB()
103
  {
104
  	return this.totalMB;
105
  }
106
  
107
/**
108
* get free disk space in MB
109
* @return free disk space in MB
110
*/
111
  public long getFreeMB()
112
  {
113
  	return this.freeMB;
114
  }
115
116
/**
117
* get trunk free space in MB
118
* @return trunk free space in MB
119
*/
120
  public long getTrunkFreeMB()
121
  {
122
  	return this.trunkFreeMB;
123
  }
124
125
/**
126
* get storage server count in this group
127
* @return storage server count in this group
128
*/
129
  public int getStorageCount()
130
  {
131
  	return this.storageCount;
132
  }
133
  
134
/**
135
* get active storage server count in this group
136
* @return active storage server count in this group
137
*/
138
  public int getActiveCount()
139
  {
140
  	return this.activeCount;
141
  }
142
  
143
/**
144
* get storage server port
145
* @return storage server port
146
*/
147
  public int getStoragePort()
148
  {
149
  	return this.storagePort;
150
  }
151
  
152
/**
153
* get storage server HTTP port
154
* @return storage server HTTP port
155
*/
156
  public int getStorageHttpPort()
157
  {
158
  	return this.storageHttpPort;
159
  }
160
161
/**
162
* get current storage server index to upload file
163
* @return current storage server index to upload file
164
*/
165
  public int getCurrentWriteServer()
166
  {
167
  	return this.currentWriteServer;
168
  }
169
  
170
/**
171
* get store base path count of each storage server
172
* @return store base path count of each storage server
173
*/
174
  public int getStorePathCount()
175
  {
176
  	return this.storePathCount;
177
  }
178
  
179
/**
180
* get sub dir count per store path
181
* @return sub dir count per store path
182
*/
183
  public int getSubdirCountPerPath()
184
  {
185
  	return this.subdirCountPerPath;
186
  }
187
  
188
/**
189
* get current trunk file id
190
* @return current trunk file id
191
*/
192
  public int getCurrentTrunkFileId()
193
  {
194
  	return this.currentTrunkFileId;
195
  }
196
  
197
/**
198
* set fields
199
* @param bs byte array
200
* @param offset start offset
201
*/
202
	public void setFields(byte[] bs, int offset)
203
	{
204
		this.groupName = stringValue(bs, offset, fieldsArray[FIELD_INDEX_GROUP_NAME]);
205
		this.totalMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MB]);
206
		this.freeMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_FREE_MB]);
207
		this.trunkFreeMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_TRUNK_FREE_MB]);
208
		this.storageCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_COUNT]);
209
	  this.storagePort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_PORT]);
210
	  this.storageHttpPort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT]);
211
	  this.activeCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_ACTIVE_COUNT]);
212
	  this.currentWriteServer = intValue(bs, offset, fieldsArray[FIELD_INDEX_CURRENT_WRITE_SERVER]);
213
	  this.storePathCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORE_PATH_COUNT]);
214
	  this.subdirCountPerPath = intValue(bs, offset, fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH]);
215
	  this.currentTrunkFileId = intValue(bs, offset, fieldsArray[FIELD_INDEX_CURRENT_TRUNK_FILE_ID]);
216
	}
217
218
/**
219
* get fields total size
220
* @return fields total size
221
*/
222
	public static int getFieldsTotalSize()
223
	{
224
		return fieldsTotalSize;
225
	}
226
}

+ 934 - 0
src/main/java/org/csource/fastdfs/StructStorageStat.java

@ -0,0 +1,934 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.util.Date;
12
13
/**
14
* C struct body decoder
15
* @author Happy Fish / YuQing
16
* @version Version 1.20
17
*/
18
public class StructStorageStat extends StructBase
19
{
20
	protected static final int FIELD_INDEX_STATUS                   = 0;
21
	protected static final int FIELD_INDEX_ID                       = 1;
22
	protected static final int FIELD_INDEX_IP_ADDR                  = 2;
23
	protected static final int FIELD_INDEX_DOMAIN_NAME              = 3;
24
	protected static final int FIELD_INDEX_SRC_IP_ADDR              = 4;
25
	protected static final int FIELD_INDEX_VERSION                  = 5;
26
	protected static final int FIELD_INDEX_JOIN_TIME                = 6;
27
	protected static final int FIELD_INDEX_UP_TIME                  = 7;
28
	protected static final int FIELD_INDEX_TOTAL_MB                 = 8;
29
	protected static final int FIELD_INDEX_FREE_MB                  = 9;
30
	protected static final int FIELD_INDEX_UPLOAD_PRIORITY          = 10;
31
	protected static final int FIELD_INDEX_STORE_PATH_COUNT         = 11;
32
	protected static final int FIELD_INDEX_SUBDIR_COUNT_PER_PATH    = 12;
33
	protected static final int FIELD_INDEX_CURRENT_WRITE_PATH       = 13;
34
	protected static final int FIELD_INDEX_STORAGE_PORT             = 14;
35
	protected static final int FIELD_INDEX_STORAGE_HTTP_PORT        = 15;
36
	protected static final int FIELD_INDEX_TOTAL_UPLOAD_COUNT       = 16;
37
	protected static final int FIELD_INDEX_SUCCESS_UPLOAD_COUNT     = 17;
38
	protected static final int FIELD_INDEX_TOTAL_APPEND_COUNT       = 18;
39
	protected static final int FIELD_INDEX_SUCCESS_APPEND_COUNT     = 19;
40
	protected static final int FIELD_INDEX_TOTAL_MODIFY_COUNT       = 20;
41
	protected static final int FIELD_INDEX_SUCCESS_MODIFY_COUNT     = 21;
42
	protected static final int FIELD_INDEX_TOTAL_TRUNCATE_COUNT     = 22;
43
	protected static final int FIELD_INDEX_SUCCESS_TRUNCATE_COUNT   = 23;
44
	protected static final int FIELD_INDEX_TOTAL_SET_META_COUNT     = 24;
45
	protected static final int FIELD_INDEX_SUCCESS_SET_META_COUNT   = 25;
46
	protected static final int FIELD_INDEX_TOTAL_DELETE_COUNT       = 26;
47
	protected static final int FIELD_INDEX_SUCCESS_DELETE_COUNT     = 27;
48
	protected static final int FIELD_INDEX_TOTAL_DOWNLOAD_COUNT     = 28;
49
	protected static final int FIELD_INDEX_SUCCESS_DOWNLOAD_COUNT   = 29;
50
	protected static final int FIELD_INDEX_TOTAL_GET_META_COUNT     = 30;
51
	protected static final int FIELD_INDEX_SUCCESS_GET_META_COUNT   = 31;
52
	protected static final int FIELD_INDEX_TOTAL_CREATE_LINK_COUNT  = 32;
53
	protected static final int FIELD_INDEX_SUCCESS_CREATE_LINK_COUNT= 33;
54
	protected static final int FIELD_INDEX_TOTAL_DELETE_LINK_COUNT  = 34;
55
	protected static final int FIELD_INDEX_SUCCESS_DELETE_LINK_COUNT= 35;	
56
	protected static final int FIELD_INDEX_TOTAL_UPLOAD_BYTES       = 36;
57
	protected static final int FIELD_INDEX_SUCCESS_UPLOAD_BYTES     = 37;
58
	protected static final int FIELD_INDEX_TOTAL_APPEND_BYTES       = 38;
59
	protected static final int FIELD_INDEX_SUCCESS_APPEND_BYTES     = 39;
60
	protected static final int FIELD_INDEX_TOTAL_MODIFY_BYTES       = 40;
61
	protected static final int FIELD_INDEX_SUCCESS_MODIFY_BYTES     = 41;
62
	protected static final int FIELD_INDEX_TOTAL_DOWNLOAD_BYTES     = 42;
63
	protected static final int FIELD_INDEX_SUCCESS_DOWNLOAD_BYTES   = 43;
64
	protected static final int FIELD_INDEX_TOTAL_SYNC_IN_BYTES      = 44;
65
	protected static final int FIELD_INDEX_SUCCESS_SYNC_IN_BYTES    = 45;
66
	protected static final int FIELD_INDEX_TOTAL_SYNC_OUT_BYTES     = 46;
67
	protected static final int FIELD_INDEX_SUCCESS_SYNC_OUT_BYTES   = 47;
68
	protected static final int FIELD_INDEX_TOTAL_FILE_OPEN_COUNT    = 48;
69
	protected static final int FIELD_INDEX_SUCCESS_FILE_OPEN_COUNT  = 49;
70
	protected static final int FIELD_INDEX_TOTAL_FILE_READ_COUNT    = 50;
71
	protected static final int FIELD_INDEX_SUCCESS_FILE_READ_COUNT  = 51;
72
	protected static final int FIELD_INDEX_TOTAL_FILE_WRITE_COUNT   = 52;
73
	protected static final int FIELD_INDEX_SUCCESS_FILE_WRITE_COUNT = 53;
74
	protected static final int FIELD_INDEX_LAST_SOURCE_UPDATE       = 54;
75
	protected static final int FIELD_INDEX_LAST_SYNC_UPDATE         = 55;
76
	protected static final int FIELD_INDEX_LAST_SYNCED_TIMESTAMP    = 56;
77
	protected static final int FIELD_INDEX_LAST_HEART_BEAT_TIME     = 57;
78
	protected static final int FIELD_INDEX_IF_TRUNK_FILE            = 58;
79
	
80
	protected static int fieldsTotalSize;
81
	protected static StructBase.FieldInfo[] fieldsArray = new StructBase.FieldInfo[59];
82
	
83
	static
84
	{
85
		int offset = 0;
86
		
87
		fieldsArray[FIELD_INDEX_STATUS] = new StructBase.FieldInfo("status", offset, 1);
88
		offset += 1;
89
		
90
		fieldsArray[FIELD_INDEX_ID] = new StructBase.FieldInfo("id", offset, ProtoCommon.FDFS_STORAGE_ID_MAX_SIZE);
91
		offset += ProtoCommon.FDFS_STORAGE_ID_MAX_SIZE;
92
		
93
		fieldsArray[FIELD_INDEX_IP_ADDR] = new StructBase.FieldInfo("ipAddr", offset, ProtoCommon.FDFS_IPADDR_SIZE);
94
		offset += ProtoCommon.FDFS_IPADDR_SIZE;
95
		
96
		fieldsArray[FIELD_INDEX_DOMAIN_NAME] = new StructBase.FieldInfo("domainName", offset, ProtoCommon.FDFS_DOMAIN_NAME_MAX_SIZE);
97
		offset += ProtoCommon.FDFS_DOMAIN_NAME_MAX_SIZE;
98
99
		fieldsArray[FIELD_INDEX_SRC_IP_ADDR] = new StructBase.FieldInfo("srcIpAddr", offset, ProtoCommon.FDFS_IPADDR_SIZE);
100
		offset += ProtoCommon.FDFS_IPADDR_SIZE;
101
				
102
		fieldsArray[FIELD_INDEX_VERSION] = new StructBase.FieldInfo("version", offset, ProtoCommon.FDFS_VERSION_SIZE);
103
		offset += ProtoCommon.FDFS_VERSION_SIZE;
104
		
105
		fieldsArray[FIELD_INDEX_JOIN_TIME] = new StructBase.FieldInfo("joinTime", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
106
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
107
		
108
		fieldsArray[FIELD_INDEX_UP_TIME] = new StructBase.FieldInfo("upTime", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
109
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
110
111
		fieldsArray[FIELD_INDEX_TOTAL_MB] = new StructBase.FieldInfo("totalMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
112
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
113
		
114
		fieldsArray[FIELD_INDEX_FREE_MB] = new StructBase.FieldInfo("freeMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
115
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
116
117
		fieldsArray[FIELD_INDEX_UPLOAD_PRIORITY] = new StructBase.FieldInfo("uploadPriority", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
118
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
119
				
120
		fieldsArray[FIELD_INDEX_STORE_PATH_COUNT] = new StructBase.FieldInfo("storePathCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
121
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
122
		
123
		fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH] = new StructBase.FieldInfo("subdirCountPerPath", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
124
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
125
126
		fieldsArray[FIELD_INDEX_CURRENT_WRITE_PATH] = new StructBase.FieldInfo("currentWritePath", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
127
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
128
129
		fieldsArray[FIELD_INDEX_STORAGE_PORT] = new StructBase.FieldInfo("storagePort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
130
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
131
		
132
		fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT] = new StructBase.FieldInfo("storageHttpPort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
133
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
134
				
135
		fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_COUNT] = new StructBase.FieldInfo("totalUploadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
136
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
137
				
138
		fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_COUNT] = new StructBase.FieldInfo("successUploadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
139
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
140
		
141
		fieldsArray[FIELD_INDEX_TOTAL_APPEND_COUNT] = new StructBase.FieldInfo("totalAppendCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
142
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
143
				
144
		fieldsArray[FIELD_INDEX_SUCCESS_APPEND_COUNT] = new StructBase.FieldInfo("successAppendCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
145
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
146
147
		fieldsArray[FIELD_INDEX_TOTAL_MODIFY_COUNT] = new StructBase.FieldInfo("totalModifyCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
148
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
149
				
150
		fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_COUNT] = new StructBase.FieldInfo("successModifyCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
151
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
152
153
		fieldsArray[FIELD_INDEX_TOTAL_TRUNCATE_COUNT] = new StructBase.FieldInfo("totalTruncateCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
154
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
155
				
156
		fieldsArray[FIELD_INDEX_SUCCESS_TRUNCATE_COUNT] = new StructBase.FieldInfo("successTruncateCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
157
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
158
		
159
		fieldsArray[FIELD_INDEX_TOTAL_SET_META_COUNT] = new StructBase.FieldInfo("totalSetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
160
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
161
		
162
		fieldsArray[FIELD_INDEX_SUCCESS_SET_META_COUNT] = new StructBase.FieldInfo("successSetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
163
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
164
		
165
		fieldsArray[FIELD_INDEX_TOTAL_DELETE_COUNT] = new StructBase.FieldInfo("totalDeleteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
166
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
167
		
168
		fieldsArray[FIELD_INDEX_SUCCESS_DELETE_COUNT] = new StructBase.FieldInfo("successDeleteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
169
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
170
		
171
		fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_COUNT] = new StructBase.FieldInfo("totalDownloadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
172
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
173
		
174
		fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_COUNT] = new StructBase.FieldInfo("successDownloadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
175
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
176
		
177
		fieldsArray[FIELD_INDEX_TOTAL_GET_META_COUNT] = new StructBase.FieldInfo("totalGetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
178
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
179
		
180
		fieldsArray[FIELD_INDEX_SUCCESS_GET_META_COUNT] = new StructBase.FieldInfo("successGetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
181
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
182
		
183
		fieldsArray[FIELD_INDEX_TOTAL_CREATE_LINK_COUNT] = new StructBase.FieldInfo("totalCreateLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
184
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
185
		
186
		fieldsArray[FIELD_INDEX_SUCCESS_CREATE_LINK_COUNT] = new StructBase.FieldInfo("successCreateLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
187
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
188
		
189
		fieldsArray[FIELD_INDEX_TOTAL_DELETE_LINK_COUNT] = new StructBase.FieldInfo("totalDeleteLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
190
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
191
		
192
		fieldsArray[FIELD_INDEX_SUCCESS_DELETE_LINK_COUNT] = new StructBase.FieldInfo("successDeleteLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
193
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
194
				
195
		fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_BYTES] = new StructBase.FieldInfo("totalUploadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
196
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
197
		
198
		fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_BYTES] = new StructBase.FieldInfo("successUploadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
199
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
200
		
201
		fieldsArray[FIELD_INDEX_TOTAL_APPEND_BYTES] = new StructBase.FieldInfo("totalAppendBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
202
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
203
		
204
		fieldsArray[FIELD_INDEX_SUCCESS_APPEND_BYTES] = new StructBase.FieldInfo("successAppendBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
205
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
206
		
207
		fieldsArray[FIELD_INDEX_TOTAL_MODIFY_BYTES] = new StructBase.FieldInfo("totalModifyBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
208
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
209
		
210
		fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_BYTES] = new StructBase.FieldInfo("successModifyBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
211
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
212
		
213
		fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_BYTES] = new StructBase.FieldInfo("totalDownloadloadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
214
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
215
		
216
		fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_BYTES] = new StructBase.FieldInfo("successDownloadloadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
217
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
218
219
		fieldsArray[FIELD_INDEX_TOTAL_SYNC_IN_BYTES] = new StructBase.FieldInfo("totalSyncInBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
220
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
221
		
222
		fieldsArray[FIELD_INDEX_SUCCESS_SYNC_IN_BYTES] = new StructBase.FieldInfo("successSyncInBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
223
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
224
225
		fieldsArray[FIELD_INDEX_TOTAL_SYNC_OUT_BYTES] = new StructBase.FieldInfo("totalSyncOutBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
226
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
227
		
228
		fieldsArray[FIELD_INDEX_SUCCESS_SYNC_OUT_BYTES] = new StructBase.FieldInfo("successSyncOutBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
229
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
230
		
231
		fieldsArray[FIELD_INDEX_TOTAL_FILE_OPEN_COUNT] = new StructBase.FieldInfo("totalFileOpenCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
232
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
233
		
234
		fieldsArray[FIELD_INDEX_SUCCESS_FILE_OPEN_COUNT] = new StructBase.FieldInfo("successFileOpenCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
235
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
236
237
		fieldsArray[FIELD_INDEX_TOTAL_FILE_READ_COUNT] = new StructBase.FieldInfo("totalFileReadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
238
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
239
		
240
		fieldsArray[FIELD_INDEX_SUCCESS_FILE_READ_COUNT] = new StructBase.FieldInfo("successFileReadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
241
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
242
		
243
		fieldsArray[FIELD_INDEX_TOTAL_FILE_WRITE_COUNT] = new StructBase.FieldInfo("totalFileWriteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
244
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
245
		
246
		fieldsArray[FIELD_INDEX_SUCCESS_FILE_WRITE_COUNT] = new StructBase.FieldInfo("successFileWriteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
247
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
248
        
249
		fieldsArray[FIELD_INDEX_LAST_SOURCE_UPDATE] = new StructBase.FieldInfo("lastSourceUpdate", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
250
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
251
		
252
		fieldsArray[FIELD_INDEX_LAST_SYNC_UPDATE] = new StructBase.FieldInfo("lastSyncUpdate", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
253
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
254
		
255
		fieldsArray[FIELD_INDEX_LAST_SYNCED_TIMESTAMP] = new StructBase.FieldInfo("lastSyncedTimestamp", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
256
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
257
		
258
		fieldsArray[FIELD_INDEX_LAST_HEART_BEAT_TIME] = new StructBase.FieldInfo("lastHeartBeatTime", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
259
		offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
260
		
261
		fieldsArray[FIELD_INDEX_IF_TRUNK_FILE] = new StructBase.FieldInfo("ifTrunkServer", offset, 1);
262
		offset += 1;
263
		
264
		fieldsTotalSize = offset;
265
	}
266
	
267
	protected byte status;
268
	protected String id;
269
	protected String ipAddr;
270
	protected String srcIpAddr;
271
	protected String domainName; //http domain name
272
	protected String version;
273
	protected long totalMB; //total disk storage in MB
274
	protected long freeMB;  //free disk storage in MB
275
	protected int uploadPriority;  //upload priority
276
	protected Date joinTime; //storage join timestamp (create timestamp)
277
	protected Date upTime;   //storage service started timestamp
278
	protected int storePathCount;  //store base path count of each storage server
279
	protected int subdirCountPerPath;
280
	protected int storagePort;
281
	protected int storageHttpPort; //storage http server port
282
	protected int currentWritePath; //current write path index
283
	protected long totalUploadCount;
284
	protected long successUploadCount;
285
	protected long totalAppendCount;
286
	protected long successAppendCount;
287
	protected long totalModifyCount;
288
	protected long successModifyCount;
289
	protected long totalTruncateCount;
290
	protected long successTruncateCount;
291
	protected long totalSetMetaCount;
292
	protected long successSetMetaCount;
293
	protected long totalDeleteCount;
294
	protected long successDeleteCount;
295
	protected long totalDownloadCount;
296
	protected long successDownloadCount;
297
	protected long totalGetMetaCount;
298
	protected long successGetMetaCount;
299
	protected long totalCreateLinkCount;
300
	protected long successCreateLinkCount;
301
	protected long totalDeleteLinkCount;
302
	protected long successDeleteLinkCount;
303
	protected long totalUploadBytes;
304
	protected long successUploadBytes;
305
	protected long totalAppendBytes;
306
	protected long successAppendBytes;
307
	protected long totalModifyBytes;
308
	protected long successModifyBytes;
309
	protected long totalDownloadloadBytes;
310
	protected long successDownloadloadBytes;
311
	protected long totalSyncInBytes;
312
	protected long successSyncInBytes;
313
	protected long totalSyncOutBytes;
314
	protected long successSyncOutBytes;
315
	protected long totalFileOpenCount;
316
	protected long successFileOpenCount;
317
	protected long totalFileReadCount;
318
	protected long successFileReadCount;
319
	protected long totalFileWriteCount;
320
	protected long successFileWriteCount;
321
	protected Date lastSourceUpdate;
322
	protected Date lastSyncUpdate;
323
	protected Date lastSyncedTimestamp;
324
	protected Date lastHeartBeatTime;
325
  protected boolean ifTrunkServer;
326
  
327
/**
328
* get storage status
329
* @return storage status
330
*/
331
  public byte getStatus()
332
  {
333
  	return this.status;
334
  }
335
  
336
/**
337
* get storage server id
338
* @return storage server id
339
*/
340
  public String getId()
341
  {
342
  	return this.id;
343
  }
344
345
/**
346
* get storage server ip address
347
* @return storage server ip address
348
*/
349
  public String getIpAddr()
350
  {
351
  	return this.ipAddr;
352
  }
353
  
354
/**
355
* get source storage ip address
356
* @return source storage ip address
357
*/
358
  public String getSrcIpAddr()
359
  {
360
  	return this.srcIpAddr;
361
  }
362
  
363
/**
364
* get the domain name of the storage server
365
* @return the domain name of the storage server
366
*/
367
  public String getDomainName()
368
  {
369
  	return this.domainName;
370
  }
371
372
/**
373
* get storage version
374
* @return storage version
375
*/
376
  public String getVersion()
377
  {
378
  	return this.version;
379
  }
380
  
381
/**
382
* get total disk space in MB
383
* @return total disk space in MB
384
*/
385
  public long getTotalMB()
386
  {
387
  	return this.totalMB;
388
  }
389
  
390
/**
391
* get free disk space in MB
392
* @return free disk space in MB
393
*/
394
  public long getFreeMB()
395
  {
396
  	return this.freeMB;
397
  }
398
	
399
/**
400
* get storage server upload priority
401
* @return storage server upload priority
402
*/
403
  public int getUploadPriority()
404
  {
405
  	return this.uploadPriority;
406
  }
407
  
408
/**
409
* get storage server join time
410
* @return storage server join time
411
*/
412
  public Date getJoinTime()
413
  {
414
  	return this.joinTime;
415
  }
416
  
417
/**
418
* get storage server up time
419
* @return storage server up time
420
*/
421
  public Date getUpTime()
422
  {
423
  	return this.upTime;
424
  }
425
426
/**
427
* get store base path count of each storage server
428
* @return store base path count of each storage server
429
*/
430
  public int getStorePathCount()
431
  {
432
  	return this.storePathCount;
433
  }
434
  
435
/**
436
* get sub dir count per store path
437
* @return sub dir count per store path
438
*/
439
  public int getSubdirCountPerPath()
440
  {
441
  	return this.subdirCountPerPath;
442
  }
443
  
444
/**
445
* get storage server port
446
* @return storage server port
447
*/
448
  public int getStoragePort()
449
  {
450
  	return this.storagePort;
451
  }
452
  
453
/**
454
* get storage server HTTP port
455
* @return storage server HTTP port
456
*/
457
  public int getStorageHttpPort()
458
  {
459
  	return this.storageHttpPort;
460
  }
461
462
/**
463
* get current write path index
464
* @return current write path index
465
*/
466
  public int getCurrentWritePath()
467
  {
468
  	return this.currentWritePath;
469
  }
470
471
/**
472
* get total upload file count
473
* @return total upload file count
474
*/
475
  public long getTotalUploadCount()
476
  {
477
  	return this.totalUploadCount;
478
  }
479
480
/**
481
* get success upload file count
482
* @return success upload file count
483
*/
484
  public long getSuccessUploadCount()
485
  {
486
  	return this.successUploadCount;
487
  }
488
489
/**
490
* get total append count
491
* @return total append count
492
*/
493
  public long getTotalAppendCount()
494
  {
495
  	return this.totalAppendCount;
496
  }
497
498
/**
499
* get success append count
500
* @return success append count
501
*/
502
  public long getSuccessAppendCount()
503
  {
504
  	return this.successAppendCount;
505
  }
506
  
507
/**
508
* get total modify count
509
* @return total modify count
510
*/
511
  public long getTotalModifyCount()
512
  {
513
  	return this.totalModifyCount;
514
  }
515
516
/**
517
* get success modify count
518
* @return success modify count
519
*/
520
  public long getSuccessModifyCount()
521
  {
522
  	return this.successModifyCount;
523
  }
524
  
525
/**
526
* get total truncate count
527
* @return total truncate count
528
*/
529
  public long getTotalTruncateCount()
530
  {
531
  	return this.totalTruncateCount;
532
  }
533
534
/**
535
* get success truncate count
536
* @return success truncate count
537
*/
538
  public long getSuccessTruncateCount()
539
  {
540
  	return this.successTruncateCount;
541
  }
542
  
543
/**
544
* get total set meta data count
545
* @return total set meta data count
546
*/
547
  public long getTotalSetMetaCount()
548
  {
549
  	return this.totalSetMetaCount;
550
  }
551
  
552
/**
553
* get success set meta data count
554
* @return success set meta data count
555
*/
556
  public long getSuccessSetMetaCount()
557
  {
558
  	return this.successSetMetaCount;
559
  }
560
  
561
/**
562
* get total delete file count
563
* @return total delete file count
564
*/
565
  public long getTotalDeleteCount()
566
  {
567
  	return this.totalDeleteCount;
568
  }
569
570
/**
571
* get success delete file count
572
* @return success delete file count
573
*/
574
  public long getSuccessDeleteCount()
575
  {
576
  	return this.successDeleteCount;
577
  }
578
  
579
/**
580
* get total download file count
581
* @return total download file count
582
*/
583
  public long getTotalDownloadCount()
584
  {
585
  	return this.totalDownloadCount;
586
  }
587
588
/**
589
* get success download file count
590
* @return success download file count
591
*/
592
  public long getSuccessDownloadCount()
593
  {
594
  	return this.successDownloadCount;
595
  }
596
597
/**
598
* get total get metadata count
599
* @return total get metadata count
600
*/
601
  public long getTotalGetMetaCount()
602
  {
603
  	return this.totalGetMetaCount;
604
  }
605
606
/**
607
* get success get metadata count
608
* @return success get metadata count
609
*/
610
  public long getSuccessGetMetaCount()
611
  {
612
  	return this.successGetMetaCount;
613
  }
614
615
/**
616
* get total create linke count
617
* @return total create linke count
618
*/
619
  public long getTotalCreateLinkCount()
620
  {
621
  	return this.totalCreateLinkCount;
622
  }
623
624
/**
625
* get success create linke count
626
* @return success create linke count
627
*/
628
  public long getSuccessCreateLinkCount()
629
  {
630
  	return this.successCreateLinkCount;
631
  }
632
  
633
/**
634
* get total delete link count
635
* @return total delete link count
636
*/
637
  public long getTotalDeleteLinkCount()
638
  {
639
  	return this.totalDeleteLinkCount;
640
  }
641
  
642
/**
643
* get success delete link count
644
* @return success delete link count
645
*/
646
  public long getSuccessDeleteLinkCount()
647
  {
648
  	return this.successDeleteLinkCount;
649
  }
650
651
/**
652
* get total upload file bytes
653
* @return total upload file bytes
654
*/
655
  public long getTotalUploadBytes()
656
  {
657
  	return this.totalUploadBytes;
658
  }
659
  
660
/**
661
* get success upload file bytes
662
* @return success upload file bytes
663
*/
664
  public long getSuccessUploadBytes()
665
  {
666
  	return this.successUploadBytes;
667
  }
668
669
/**
670
* get total append bytes
671
* @return total append bytes
672
*/
673
  public long getTotalAppendBytes()
674
  {
675
  	return this.totalAppendBytes;
676
  }
677
  
678
/**
679
* get success append bytes
680
* @return success append bytes
681
*/
682
  public long getSuccessAppendBytes()
683
  {
684
  	return this.successAppendBytes;
685
  }
686
687
/**
688
* get total modify bytes
689
* @return total modify bytes
690
*/
691
  public long getTotalModifyBytes()
692
  {
693
  	return this.totalModifyBytes;
694
  }
695
  
696
/**
697
* get success modify bytes
698
* @return success modify bytes
699
*/
700
  public long getSuccessModifyBytes()
701
  {
702
  	return this.successModifyBytes;
703
  }
704
  
705
/**
706
* get total download file bytes
707
* @return total download file bytes
708
*/
709
  public long getTotalDownloadloadBytes()
710
  {
711
  	return this.totalDownloadloadBytes;
712
  }
713
  
714
/**
715
* get success download file bytes
716
* @return success download file bytes
717
*/
718
  public long getSuccessDownloadloadBytes()
719
  {
720
  	return this.successDownloadloadBytes;
721
  }
722
723
/**
724
* get total sync in bytes
725
* @return total sync in bytes
726
*/
727
  public long getTotalSyncInBytes()
728
  {
729
  	return this.totalSyncInBytes;
730
  }
731
  
732
/**
733
* get success sync in bytes
734
* @return success sync in bytes
735
*/
736
  public long getSuccessSyncInBytes()
737
  {
738
  	return this.successSyncInBytes;
739
  }
740
741
/**
742
* get total sync out bytes
743
* @return total sync out bytes
744
*/
745
  public long getTotalSyncOutBytes()
746
  {
747
  	return this.totalSyncOutBytes;
748
  }
749
  
750
/**
751
* get success sync out bytes
752
* @return success sync out bytes
753
*/
754
  public long getSuccessSyncOutBytes()
755
  {
756
  	return this.successSyncOutBytes;
757
  }
758
759
/**
760
* get total file opened count
761
* @return total file opened bytes
762
*/
763
  public long getTotalFileOpenCount()
764
  {
765
  	return this.totalFileOpenCount;
766
  }
767
  
768
/**
769
* get success file opened count
770
* @return success file opened count
771
*/
772
  public long getSuccessFileOpenCount()
773
  {
774
  	return this.successFileOpenCount;
775
  }
776
777
/**
778
* get total file read count
779
* @return total file read bytes
780
*/
781
  public long getTotalFileReadCount()
782
  {
783
  	return this.totalFileReadCount;
784
  }
785
  
786
/**
787
* get success file read count
788
* @return success file read count
789
*/
790
  public long getSuccessFileReadCount()
791
  {
792
  	return this.successFileReadCount;
793
  }
794
795
/**
796
* get total file write count
797
* @return total file write bytes
798
*/
799
  public long getTotalFileWriteCount()
800
  {
801
  	return this.totalFileWriteCount;
802
  }
803
  
804
/**
805
* get success file write count
806
* @return success file write count
807
*/
808
  public long getSuccessFileWriteCount()
809
  {
810
  	return this.successFileWriteCount;
811
  }
812
  
813
/**
814
* get last source update timestamp
815
* @return last source update timestamp
816
*/
817
  public Date getLastSourceUpdate()
818
  {
819
  	return this.lastSourceUpdate;
820
  }
821
822
/**
823
* get last synced update timestamp
824
* @return last synced update timestamp
825
*/
826
  public Date getLastSyncUpdate()
827
  {
828
  	return this.lastSyncUpdate;
829
  }
830
  
831
/**
832
* get last synced timestamp
833
* @return last synced timestamp
834
*/
835
  public Date getLastSyncedTimestamp()
836
  {
837
  	return this.lastSyncedTimestamp;
838
  }
839
840
/**
841
* get last heart beat timestamp
842
* @return last heart beat timestamp
843
*/
844
  public Date getLastHeartBeatTime()
845
  {
846
  	return this.lastHeartBeatTime;
847
  }
848
849
/**
850
* if the trunk server
851
* @return true for the trunk server, otherwise false
852
*/
853
  public boolean isTrunkServer()
854
  {
855
  	return this.ifTrunkServer;
856
  }
857
  
858
/**
859
* set fields
860
* @param bs byte array
861
* @param offset start offset
862
*/
863
	public void setFields(byte[] bs, int offset)
864
	{
865
		this.status = byteValue(bs, offset, fieldsArray[FIELD_INDEX_STATUS]);
866
		this.id = stringValue(bs, offset, fieldsArray[FIELD_INDEX_ID]);
867
		this.ipAddr = stringValue(bs, offset, fieldsArray[FIELD_INDEX_IP_ADDR]);
868
		this.srcIpAddr = stringValue(bs, offset, fieldsArray[FIELD_INDEX_SRC_IP_ADDR]);
869
		this.domainName = stringValue(bs, offset, fieldsArray[FIELD_INDEX_DOMAIN_NAME]);
870
		this.version = stringValue(bs, offset, fieldsArray[FIELD_INDEX_VERSION]);
871
		this.totalMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MB]);
872
		this.freeMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_FREE_MB]);
873
		this.uploadPriority = intValue(bs, offset, fieldsArray[FIELD_INDEX_UPLOAD_PRIORITY]);
874
		this.joinTime = dateValue(bs, offset, fieldsArray[FIELD_INDEX_JOIN_TIME]);
875
		this.upTime = dateValue(bs, offset, fieldsArray[FIELD_INDEX_UP_TIME]);
876
	  this.storePathCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORE_PATH_COUNT]);
877
	  this.subdirCountPerPath = intValue(bs, offset, fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH]);
878
	  this.storagePort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_PORT]);
879
	  this.storageHttpPort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT]);
880
	  this.currentWritePath = intValue(bs, offset, fieldsArray[FIELD_INDEX_CURRENT_WRITE_PATH]);
881
		this.totalUploadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_COUNT]);
882
		this.successUploadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_COUNT]);
883
		this.totalAppendCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_APPEND_COUNT]);
884
		this.successAppendCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_APPEND_COUNT]);
885
		this.totalModifyCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MODIFY_COUNT]);
886
		this.successModifyCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_COUNT]);
887
		this.totalTruncateCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_TRUNCATE_COUNT]);
888
		this.successTruncateCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_TRUNCATE_COUNT]);
889
		this.totalSetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_SET_META_COUNT]);
890
		this.successSetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_SET_META_COUNT]);
891
		this.totalDeleteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DELETE_COUNT]);
892
		this.successDeleteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DELETE_COUNT]);
893
		this.totalDownloadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_COUNT]);
894
		this.successDownloadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_COUNT]);
895
		this.totalGetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_GET_META_COUNT]);
896
		this.successGetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_GET_META_COUNT]);
897
		this.totalCreateLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_CREATE_LINK_COUNT]);
898
		this.successCreateLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_CREATE_LINK_COUNT]);
899
		this.totalDeleteLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DELETE_LINK_COUNT]);
900
		this.successDeleteLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DELETE_LINK_COUNT]);
901
		this.totalUploadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_BYTES]);
902
		this.successUploadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_BYTES]);
903
		this.totalAppendBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_APPEND_BYTES]);
904
		this.successAppendBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_APPEND_BYTES]);
905
		this.totalModifyBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MODIFY_BYTES]);
906
		this.successModifyBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_BYTES]);
907
		this.totalDownloadloadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_BYTES]);
908
		this.successDownloadloadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_BYTES]);
909
		this.totalSyncInBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_SYNC_IN_BYTES]);
910
		this.successSyncInBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_SYNC_IN_BYTES]);
911
		this.totalSyncOutBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_SYNC_OUT_BYTES]);
912
		this.successSyncOutBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_SYNC_OUT_BYTES]);
913
		this.totalFileOpenCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_FILE_OPEN_COUNT]);
914
		this.successFileOpenCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_FILE_OPEN_COUNT]);
915
		this.totalFileReadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_FILE_READ_COUNT]);
916
		this.successFileReadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_FILE_READ_COUNT]);
917
		this.totalFileWriteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_FILE_WRITE_COUNT]);
918
		this.successFileWriteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_FILE_WRITE_COUNT]);
919
		this.lastSourceUpdate = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_SOURCE_UPDATE]);
920
		this.lastSyncUpdate = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_SYNC_UPDATE]);
921
		this.lastSyncedTimestamp = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_SYNCED_TIMESTAMP]);
922
		this.lastHeartBeatTime = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_HEART_BEAT_TIME]);
923
		this.ifTrunkServer = booleanValue(bs, offset, fieldsArray[FIELD_INDEX_IF_TRUNK_FILE]);
924
	}
925
926
/**
927
* get fields total size
928
* @return fields total size
929
*/
930
	public static int getFieldsTotalSize()
931
	{
932
		return fieldsTotalSize;
933
	}
934
}

+ 990 - 0
src/main/java/org/csource/fastdfs/TrackerClient.java

@ -0,0 +1,990 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.io.OutputStream;
13
import java.net.Socket;
14
import java.util.Arrays;
15
16
/**
17
* Tracker client
18
* @author Happy Fish / YuQing
19
* @version Version 1.19
20
*/
21
public class TrackerClient
22
{
23
	protected TrackerGroup tracker_group;
24
  protected byte errno;
25
  
26
/**
27
* constructor with global tracker group
28
*/
29
	public TrackerClient()
30
	{
31
		this.tracker_group = ClientGlobal.g_tracker_group;
32
	}
33
	
34
/**
35
* constructor with specified tracker group
36
* @param tracker_group the tracker group object
37
*/
38
	public TrackerClient(TrackerGroup tracker_group)
39
	{
40
		this.tracker_group = tracker_group;
41
	}
42
	
43
/**
44
* get the error code of last call
45
* @return the error code of last call
46
*/
47
	public byte getErrorCode()
48
	{
49
		return this.errno;
50
	}
51
	
52
	/**
53
	* get a connection to tracker server
54
	* @return tracker server Socket object, return null if fail
55
	*/
56
	public TrackerServer getConnection() throws IOException
57
	{
58
		return this.tracker_group.getConnection();
59
	}
60
	
61
	/**
62
	* query storage server to upload file
63
	* @param trackerServer the tracker server
64
	* @return storage server Socket object, return null if fail
65
	*/
66
	public StorageServer getStoreStorage(TrackerServer trackerServer) throws IOException
67
	{
68
		final String groupName = null;
69
		return this.getStoreStorage(trackerServer, groupName);
70
	}
71
	
72
	/**
73
	* query storage server to upload file
74
	* @param trackerServer the tracker server
75
	* @param groupName the group name to upload file to, can be empty
76
	* @return storage server object, return null if fail
77
	*/
78
	public StorageServer getStoreStorage(TrackerServer trackerServer, String groupName) throws IOException
79
	{
80
		byte[] header;
81
		String ip_addr;
82
		int port;
83
		byte cmd;
84
		int out_len;
85
		boolean bNewConnection;
86
		byte store_path;
87
		Socket trackerSocket;
88
		
89
		if (trackerServer == null)
90
		{
91
			trackerServer = getConnection();
92
			if (trackerServer == null)
93
			{
94
				return null;
95
			}
96
			bNewConnection = true;
97
		}
98
		else
99
		{
100
			bNewConnection = false;
101
		}
102
103
		trackerSocket = trackerServer.getSocket();
104
		OutputStream out = trackerSocket.getOutputStream();
105
		
106
		try
107
		{
108
			if (groupName == null || groupName.length() == 0)
109
			{
110
				cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE;
111
				out_len = 0;
112
			}
113
			else
114
			{
115
				cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE;
116
				out_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
117
			}
118
			header = ProtoCommon.packHeader(cmd, out_len, (byte)0);
119
			out.write(header);
120
121
			if (groupName != null && groupName.length() > 0)
122
			{
123
				byte[] bGroupName;
124
				byte[] bs;
125
				int group_len;
126
				
127
				bs = groupName.getBytes(ClientGlobal.g_charset);
128
				bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
129
				
130
				if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN)
131
				{
132
					group_len = bs.length;
133
				}
134
				else
135
				{
136
					group_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
137
				}
138
				Arrays.fill(bGroupName, (byte)0);
139
				System.arraycopy(bs, 0, bGroupName, 0, group_len);
140
				out.write(bGroupName);
141
			}
142
	
143
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), 
144
	                                     ProtoCommon.TRACKER_PROTO_CMD_RESP, 
145
	                                     ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN);
146
			this.errno = pkgInfo.errno;
147
			if (pkgInfo.errno != 0)
148
			{
149
				return null;
150
			}
151
			
152
			ip_addr = new String(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN, ProtoCommon.FDFS_IPADDR_SIZE-1).trim();
153
	
154
			port = (int)ProtoCommon.buff2long(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN
155
	                        + ProtoCommon.FDFS_IPADDR_SIZE-1);
156
			store_path = pkgInfo.body[ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN - 1];
157
			
158
			return new StorageServer(ip_addr, port, store_path);
159
		}
160
		catch(IOException ex)
161
		{
162
			if (!bNewConnection)
163
			{
164
				try
165
				{
166
					trackerServer.close();
167
				}
168
				catch(IOException ex1)
169
				{
170
					ex1.printStackTrace();
171
				}
172
			}
173
			
174
			throw ex;
175
		}
176
		finally
177
		{
178
			if (bNewConnection)
179
			{
180
				try
181
				{
182
					trackerServer.close();
183
				}
184
				catch(IOException ex1)
185
				{
186
					ex1.printStackTrace();
187
				}
188
			}
189
		}
190
	}
191
192
	/**
193
	* query storage servers to upload file
194
	* @param trackerServer the tracker server
195
	* @param groupName the group name to upload file to, can be empty
196
	* @return storage servers, return null if fail
197
	*/
198
	public StorageServer[] getStoreStorages(TrackerServer trackerServer, String groupName) throws IOException
199
	{
200
		byte[] header;
201
		String ip_addr;
202
		int port;
203
		byte cmd;
204
		int out_len;
205
		boolean bNewConnection;
206
		Socket trackerSocket;
207
		
208
		if (trackerServer == null)
209
		{
210
			trackerServer = getConnection();
211
			if (trackerServer == null)
212
			{
213
				return null;
214
			}
215
			bNewConnection = true;
216
		}
217
		else
218
		{
219
			bNewConnection = false;
220
		}
221
222
		trackerSocket = trackerServer.getSocket();
223
		OutputStream out = trackerSocket.getOutputStream();
224
		
225
		try
226
		{
227
			if (groupName == null || groupName.length() == 0)
228
			{
229
				cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL;
230
				out_len = 0;
231
			}
232
			else
233
			{
234
				cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL;
235
				out_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
236
			}
237
			header = ProtoCommon.packHeader(cmd, out_len, (byte)0);
238
			out.write(header);
239
240
			if (groupName != null && groupName.length() > 0)
241
			{
242
				byte[] bGroupName;
243
				byte[] bs;
244
				int group_len;
245
				
246
				bs = groupName.getBytes(ClientGlobal.g_charset);
247
				bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
248
				
249
				if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN)
250
				{
251
					group_len = bs.length;
252
				}
253
				else
254
				{
255
					group_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
256
				}
257
				Arrays.fill(bGroupName, (byte)0);
258
				System.arraycopy(bs, 0, bGroupName, 0, group_len);
259
				out.write(bGroupName);
260
			}
261
	
262
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), 
263
	                                     ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
264
			this.errno = pkgInfo.errno;
265
			if (pkgInfo.errno != 0)
266
			{
267
				return null;
268
			}
269
			
270
			if (pkgInfo.body.length < ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN)
271
			{
272
				this.errno = ProtoCommon.ERR_NO_EINVAL;
273
				return null;
274
			}
275
			
276
			int ipPortLen = pkgInfo.body.length - (ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1);
277
			final int recordLength = ProtoCommon.FDFS_IPADDR_SIZE - 1 + ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
278
			
279
			if (ipPortLen % recordLength != 0)
280
			{
281
				this.errno = ProtoCommon.ERR_NO_EINVAL;
282
				return null;
283
			}
284
			
285
			int serverCount = ipPortLen / recordLength;
286
			if (serverCount > 16)
287
			{
288
				this.errno = ProtoCommon.ERR_NO_ENOSPC;
289
				return null;
290
			}
291
			
292
			StorageServer[] results = new StorageServer[serverCount];
293
			byte store_path = pkgInfo.body[pkgInfo.body.length - 1];
294
			int offset = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
295
			
296
			for (int i=0; i<serverCount; i++)
297
			{
298
				ip_addr = new String(pkgInfo.body, offset, ProtoCommon.FDFS_IPADDR_SIZE - 1).trim();
299
				offset += ProtoCommon.FDFS_IPADDR_SIZE - 1;
300
				
301
				port = (int)ProtoCommon.buff2long(pkgInfo.body, offset);
302
		    offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
303
		    
304
		    results[i] = new StorageServer(ip_addr, port, store_path);
305
	    }
306
	    
307
			return results;
308
		}
309
		catch(IOException ex)
310
		{
311
			if (!bNewConnection)
312
			{
313
				try
314
				{
315
					trackerServer.close();
316
				}
317
				catch(IOException ex1)
318
				{
319
					ex1.printStackTrace();
320
				}
321
			}
322
			
323
			throw ex;
324
		}
325
		finally
326
		{
327
			if (bNewConnection)
328
			{
329
				try
330
				{
331
					trackerServer.close();
332
				}
333
				catch(IOException ex1)
334
				{
335
					ex1.printStackTrace();
336
				}
337
			}
338
		}
339
	}
340
	
341
	/**
342
	* query storage server to download file
343
	* @param trackerServer the tracker server
344
	*	@param groupName the group name of storage server
345
	* @param filename filename on storage server
346
	* @return storage server Socket object, return null if fail
347
	*/
348
	public StorageServer getFetchStorage(TrackerServer trackerServer, 
349
			String groupName, String filename) throws IOException
350
	{
351
		ServerInfo[] servers = this.getStorages(trackerServer, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE,
352
				groupName, filename);
353
		if (servers == null)
354
		{
355
				return null;
356
		}
357
		else
358
		{
359
			return new StorageServer(servers[0].getIpAddr(), servers[0].getPort(), 0);
360
		}
361
	}
362
363
	/**
364
	* query storage server to update file (delete file or set meta data)
365
	* @param trackerServer the tracker server
366
	*	@param groupName the group name of storage server
367
	* @param filename filename on storage server
368
	* @return storage server Socket object, return null if fail
369
	*/
370
	public StorageServer getUpdateStorage(TrackerServer trackerServer, 
371
			String groupName, String filename) throws IOException
372
	{
373
		ServerInfo[] servers = this.getStorages(trackerServer, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE,
374
				groupName, filename);
375
		if (servers == null)
376
		{
377
				return null;
378
		}
379
		else
380
		{
381
			return new StorageServer(servers[0].getIpAddr(), servers[0].getPort(), 0);
382
		} 
383
	}
384
385
	/**
386
	* get storage servers to download file
387
	* @param trackerServer the tracker server
388
	*	@param groupName the group name of storage server
389
	* @param filename filename on storage server
390
	* @return storage servers, return null if fail
391
	*/
392
	public ServerInfo[] getFetchStorages(TrackerServer trackerServer,
393
                                         String groupName, String filename) throws IOException
394
	{
395
		return this.getStorages(trackerServer, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ALL, 
396
				groupName, filename);
397
	}
398
	
399
	/**
400
	* query storage server to download file
401
	* @param trackerServer the tracker server
402
	* @param cmd command code, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE or 
403
	                     ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE
404
	*	@param groupName the group name of storage server
405
	* @param filename filename on storage server
406
	* @return storage server Socket object, return null if fail
407
	*/
408
	protected ServerInfo[] getStorages(TrackerServer trackerServer,
409
                                       byte cmd, String groupName, String filename) throws IOException
410
	{
411
		byte[] header;
412
		byte[] bFileName;
413
		byte[] bGroupName;
414
		byte[] bs;
415
		int len;
416
		String ip_addr;
417
		int port;
418
		boolean bNewConnection;
419
		Socket trackerSocket;
420
		
421
		if (trackerServer == null)
422
		{
423
			trackerServer = getConnection();
424
			if (trackerServer == null)
425
			{
426
				return null;
427
			}
428
			bNewConnection = true;
429
		}
430
		else
431
		{
432
			bNewConnection = false;
433
		}
434
		trackerSocket = trackerServer.getSocket();
435
		OutputStream out = trackerSocket.getOutputStream();
436
		
437
		try
438
		{
439
			bs = groupName.getBytes(ClientGlobal.g_charset);
440
			bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
441
			bFileName = filename.getBytes(ClientGlobal.g_charset);
442
			
443
			if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN)
444
			{
445
				len = bs.length;
446
			}
447
			else
448
			{
449
				len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
450
			}
451
			Arrays.fill(bGroupName, (byte)0);
452
			System.arraycopy(bs, 0, bGroupName, 0, len);
453
			
454
			header = ProtoCommon.packHeader(cmd, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + bFileName.length, (byte)0);
455
			byte[] wholePkg = new byte[header.length + bGroupName.length + bFileName.length];
456
			System.arraycopy(header, 0, wholePkg, 0, header.length);
457
			System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length);
458
			System.arraycopy(bFileName, 0, wholePkg, header.length + bGroupName.length, bFileName.length);
459
			out.write(wholePkg);
460
			
461
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), 
462
	                                     ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
463
			this.errno = pkgInfo.errno;
464
			if (pkgInfo.errno != 0)
465
			{
466
				return null;
467
			}
468
			
469
			if (pkgInfo.body.length < ProtoCommon.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN)
470
			{
471
				throw new IOException("Invalid body length: " + pkgInfo.body.length);
472
			}
473
			
474
			if ((pkgInfo.body.length - ProtoCommon.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) % (ProtoCommon.FDFS_IPADDR_SIZE - 1) != 0)
475
			{
476
				throw new IOException("Invalid body length: " + pkgInfo.body.length);
477
			}
478
			
479
			int server_count = 1 + (pkgInfo.body.length - ProtoCommon.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) / (ProtoCommon.FDFS_IPADDR_SIZE - 1);
480
			
481
			ip_addr = new String(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN, ProtoCommon.FDFS_IPADDR_SIZE-1).trim();
482
			int offset = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ProtoCommon.FDFS_IPADDR_SIZE - 1;
483
			
484
			port = (int)ProtoCommon.buff2long(pkgInfo.body, offset);
485
	    offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
486
	    
487
	    ServerInfo[] servers = new ServerInfo[server_count];
488
	    servers[0] = new ServerInfo(ip_addr, port);
489
	    for (int i=1; i<server_count; i++)
490
	    {
491
	    	servers[i] = new ServerInfo(new String(pkgInfo.body, offset, ProtoCommon.FDFS_IPADDR_SIZE-1).trim(), port);
492
	    	offset += ProtoCommon.FDFS_IPADDR_SIZE - 1;
493
	    }
494
	
495
			return servers;
496
		}
497
		catch(IOException ex)
498
		{
499
			if (!bNewConnection)
500
			{
501
				try
502
				{
503
					trackerServer.close();
504
				}
505
				catch(IOException ex1)
506
				{
507
					ex1.printStackTrace();
508
				}
509
			}
510
			
511
			throw ex;
512
		}
513
		finally
514
		{
515
			if (bNewConnection)
516
			{
517
				try
518
				{
519
					trackerServer.close();
520
				}
521
				catch(IOException ex1)
522
				{
523
					ex1.printStackTrace();
524
				}
525
			}
526
		}
527
	}
528
	
529
	/**
530
	* query storage server to download file
531
	* @param trackerServer the tracker server
532
	*	@param file_id the file id(including group name and filename)
533
	* @return storage server Socket object, return null if fail
534
	*/
535
	public StorageServer getFetchStorage1(TrackerServer trackerServer, String file_id) throws IOException
536
	{
537
		String[] parts = new String[2];
538
		this.errno = StorageClient1.split_file_id(file_id, parts);
539
		if (this.errno != 0)
540
		{
541
			return null;
542
		}
543
		
544
		return this.getFetchStorage(trackerServer, parts[0], parts[1]);
545
	}
546
	
547
	/**
548
	* get storage servers to download file
549
	* @param trackerServer the tracker server
550
	*	@param file_id the file id(including group name and filename)
551
	* @return storage servers, return null if fail
552
	*/
553
	public ServerInfo[] getFetchStorages1(TrackerServer trackerServer, String file_id) throws IOException
554
	{
555
		String[] parts = new String[2];
556
		this.errno = StorageClient1.split_file_id(file_id, parts);
557
		if (this.errno != 0)
558
		{
559
			return null;
560
		}
561
		
562
		return this.getFetchStorages(trackerServer, parts[0], parts[1]);
563
	}
564
	
565
	/**
566
	* list groups
567
	* @param trackerServer the tracker server
568
	* @return group stat array, return null if fail
569
	*/
570
	public StructGroupStat[] listGroups(TrackerServer trackerServer) throws IOException
571
	{
572
		byte[] header;
573
		String ip_addr;
574
		int port;
575
		byte cmd;
576
		int out_len;
577
		boolean bNewConnection;
578
		byte store_path;
579
		Socket trackerSocket;
580
		
581
		if (trackerServer == null)
582
		{
583
			trackerServer = getConnection();
584
			if (trackerServer == null)
585
			{
586
				return null;
587
			}
588
			bNewConnection = true;
589
		}
590
		else
591
		{
592
			bNewConnection = false;
593
		}
594
595
		trackerSocket = trackerServer.getSocket();
596
		OutputStream out = trackerSocket.getOutputStream();
597
		
598
		try
599
		{
600
			header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_LIST_GROUP, 0, (byte)0);
601
			out.write(header);
602
	
603
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), 
604
	                                     ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
605
			this.errno = pkgInfo.errno;
606
			if (pkgInfo.errno != 0)
607
			{
608
				return null;
609
			}
610
			
611
			ProtoStructDecoder<StructGroupStat> decoder = new ProtoStructDecoder<StructGroupStat>();
612
			return decoder.decode(pkgInfo.body, StructGroupStat.class, StructGroupStat.getFieldsTotalSize());
613
		}
614
		catch(IOException ex)
615
		{
616
			if (!bNewConnection)
617
			{
618
				try
619
				{
620
					trackerServer.close();
621
				}
622
				catch(IOException ex1)
623
				{
624
					ex1.printStackTrace();
625
				}
626
			}
627
			
628
			throw ex;
629
		}
630
		catch(Exception ex)
631
		{
632
			ex.printStackTrace();
633
			this.errno = ProtoCommon.ERR_NO_EINVAL;
634
			return null;
635
		}
636
		finally
637
		{
638
			if (bNewConnection)
639
			{
640
				try
641
				{
642
					trackerServer.close();
643
				}
644
				catch(IOException ex1)
645
				{
646
					ex1.printStackTrace();
647
				}
648
			}
649
		}
650
	}
651
652
	/**
653
	* query storage server stat info of the group
654
	* @param trackerServer the tracker server
655
	*	@param groupName the group name of storage server
656
	* @return storage server stat array, return null if fail
657
	*/
658
	public StructStorageStat[] listStorages(TrackerServer trackerServer, String groupName) throws IOException
659
	{
660
		final String storageIpAddr = null;
661
		return this.listStorages(trackerServer, groupName, storageIpAddr);
662
	}
663
	
664
	/**
665
	* query storage server stat info of the group
666
	* @param trackerServer the tracker server
667
	*	@param groupName the group name of storage server
668
	* @param storageIpAddr the storage server ip address, can be null or empty
669
	* @return storage server stat array, return null if fail
670
	*/
671
	public StructStorageStat[] listStorages(TrackerServer trackerServer, 
672
			String groupName, String storageIpAddr) throws IOException
673
	{
674
		byte[] header;
675
		byte[] bGroupName;
676
		byte[] bs;
677
		int len;
678
		boolean bNewConnection;
679
		Socket trackerSocket;
680
		
681
		if (trackerServer == null)
682
		{
683
			trackerServer = getConnection();
684
			if (trackerServer == null)
685
			{
686
				return null;
687
			}
688
			bNewConnection = true;
689
		}
690
		else
691
		{
692
			bNewConnection = false;
693
		}
694
		trackerSocket = trackerServer.getSocket();
695
		OutputStream out = trackerSocket.getOutputStream();
696
		
697
		try
698
		{
699
			bs = groupName.getBytes(ClientGlobal.g_charset);
700
			bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
701
			
702
			if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN)
703
			{
704
				len = bs.length;
705
			}
706
			else
707
			{
708
				len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
709
			}
710
			Arrays.fill(bGroupName, (byte)0);
711
			System.arraycopy(bs, 0, bGroupName, 0, len);
712
			
713
			int ipAddrLen;
714
			byte[] bIpAddr;
715
			if (storageIpAddr != null && storageIpAddr.length() > 0)
716
			{
717
				bIpAddr = storageIpAddr.getBytes(ClientGlobal.g_charset);
718
				if (bIpAddr.length < ProtoCommon.FDFS_IPADDR_SIZE)
719
				{
720
					ipAddrLen = bIpAddr.length;
721
				}
722
				else
723
				{
724
					ipAddrLen = ProtoCommon.FDFS_IPADDR_SIZE - 1;
725
				}
726
			}
727
			else
728
			{
729
				bIpAddr = null;
730
				ipAddrLen = 0;
731
			}
732
			
733
			header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_LIST_STORAGE, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ipAddrLen, (byte)0);
734
			byte[] wholePkg = new byte[header.length + bGroupName.length + ipAddrLen];
735
			System.arraycopy(header, 0, wholePkg, 0, header.length);
736
			System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length);
737
			if (ipAddrLen > 0)
738
			{
739
				System.arraycopy(bIpAddr, 0, wholePkg, header.length + bGroupName.length, ipAddrLen);
740
			}
741
			out.write(wholePkg);
742
			
743
			ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), 
744
	                                     ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
745
			this.errno = pkgInfo.errno;
746
			if (pkgInfo.errno != 0)
747
			{
748
				return null;
749
			}
750
			
751
			ProtoStructDecoder<StructStorageStat> decoder = new ProtoStructDecoder<StructStorageStat>();
752
			return decoder.decode(pkgInfo.body, StructStorageStat.class, StructStorageStat.getFieldsTotalSize());
753
		}
754
		catch(IOException ex)
755
		{
756
			if (!bNewConnection)
757
			{
758
				try
759
				{
760
					trackerServer.close();
761
				}
762
				catch(IOException ex1)
763
				{
764
					ex1.printStackTrace();
765
				}
766
			}
767
			
768
			throw ex;
769
		}
770
		catch(Exception ex)
771
		{
772
			ex.printStackTrace();
773
			this.errno = ProtoCommon.ERR_NO_EINVAL;
774
			return null;
775
		}
776
		finally
777
		{
778
			if (bNewConnection)
779
			{
780
				try
781
				{
782
					trackerServer.close();
783
				}
784
				catch(IOException ex1)
785
				{
786
					ex1.printStackTrace();
787
				}
788
			}
789
		}
790
	}
791
792
	/**
793
	* delete a storage server from the tracker server
794
	* @param trackerServer the connected tracker server
795
	*	@param groupName the group name of storage server
796
	* @param storageIpAddr the storage server ip address
797
	* @return true for success, false for fail
798
	*/
799
	private boolean deleteStorage(TrackerServer trackerServer, 
800
			String groupName, String storageIpAddr) throws IOException
801
	{
802
		byte[] header;
803
		byte[] bGroupName;
804
		byte[] bs;
805
		int len;
806
		Socket trackerSocket;
807
		
808
		trackerSocket = trackerServer.getSocket();
809
		OutputStream out = trackerSocket.getOutputStream();
810
		
811
		bs = groupName.getBytes(ClientGlobal.g_charset);
812
		bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
813
		
814
		if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN)
815
		{
816
			len = bs.length;
817
		}
818
		else
819
		{
820
			len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
821
		}
822
		Arrays.fill(bGroupName, (byte)0);
823
		System.arraycopy(bs, 0, bGroupName, 0, len);
824
		
825
		int ipAddrLen;
826
		byte[] bIpAddr = storageIpAddr.getBytes(ClientGlobal.g_charset);
827
		if (bIpAddr.length < ProtoCommon.FDFS_IPADDR_SIZE)
828
		{
829
			ipAddrLen = bIpAddr.length;
830
		}
831
		else
832
		{
833
			ipAddrLen = ProtoCommon.FDFS_IPADDR_SIZE - 1;
834
		}
835
836
		header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ipAddrLen, (byte)0);
837
		byte[] wholePkg = new byte[header.length + bGroupName.length + ipAddrLen];
838
		System.arraycopy(header, 0, wholePkg, 0, header.length);
839
		System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length);
840
		System.arraycopy(bIpAddr, 0, wholePkg, header.length + bGroupName.length, ipAddrLen);
841
		out.write(wholePkg);
842
		
843
		ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), 
844
                                     ProtoCommon.TRACKER_PROTO_CMD_RESP, 0);
845
		this.errno = pkgInfo.errno;
846
		return pkgInfo.errno == 0;
847
	}
848
849
	/**
850
	* delete a storage server from the global FastDFS cluster
851
	*	@param groupName the group name of storage server
852
	* @param storageIpAddr the storage server ip address
853
	* @return true for success, false for fail
854
	*/
855
	public boolean deleteStorage(String groupName, String storageIpAddr) throws IOException
856
	{
857
		return this.deleteStorage(ClientGlobal.g_tracker_group, groupName, storageIpAddr);
858
	}
859
	
860
	/**
861
	* delete a storage server from the FastDFS cluster
862
	* @param trackerGroup the tracker server group
863
	*	@param groupName the group name of storage server
864
	* @param storageIpAddr the storage server ip address
865
	* @return true for success, false for fail
866
	*/
867
	public boolean deleteStorage(TrackerGroup trackerGroup, 
868
			String groupName, String storageIpAddr) throws IOException
869
	{
870
		int serverIndex;
871
		int notFoundCount;
872
		TrackerServer trackerServer;
873
				
874
		notFoundCount = 0;
875
		for (serverIndex=0; serverIndex<trackerGroup.tracker_servers.length; serverIndex++)
876
		{			
877
			try
878
			{
879
				trackerServer = trackerGroup.getConnection(serverIndex);
880
			}
881
			catch(IOException ex)
882
			{
883
		  	ex.printStackTrace(System.err);
884
		  	this.errno = ProtoCommon.ECONNREFUSED;
885
		  	return false;
886
			}
887
			
888
			try
889
			{
890
				StructStorageStat[] storageStats = listStorages(trackerServer, groupName, storageIpAddr);
891
				if (storageStats == null)
892
				{
893
					if (this.errno == ProtoCommon.ERR_NO_ENOENT)
894
					{
895
						notFoundCount++;
896
					}
897
					else
898
					{
899
						return false;
900
					}
901
				}
902
				else if (storageStats.length == 0)
903
				{
904
					notFoundCount++;
905
				}
906
				else if (storageStats[0].getStatus() == ProtoCommon.FDFS_STORAGE_STATUS_ONLINE || 
907
				         storageStats[0].getStatus() == ProtoCommon.FDFS_STORAGE_STATUS_ACTIVE)
908
				{
909
					this.errno = ProtoCommon.ERR_NO_EBUSY;
910
					return false;
911
				}
912
			}
913
			finally
914
			{
915
				try
916
				{
917
					trackerServer.close();
918
				}
919
				catch(IOException ex1)
920
				{
921
					ex1.printStackTrace();
922
				}
923
			}
924
		}
925
				
926
		if (notFoundCount == trackerGroup.tracker_servers.length)
927
		{
928
	  	this.errno = ProtoCommon.ERR_NO_ENOENT;
929
	  	return false;
930
		}
931
932
		notFoundCount = 0;
933
		for (serverIndex=0; serverIndex<trackerGroup.tracker_servers.length; serverIndex++)
934
		{
935
			try
936
			{
937
				trackerServer = trackerGroup.getConnection(serverIndex);
938
			}
939
			catch(IOException ex)
940
			{
941
		  	System.err.println("connect to server " + trackerGroup.tracker_servers[serverIndex].getAddress().getHostAddress() + ":" + trackerGroup.tracker_servers[serverIndex].getPort() + " fail");
942
		  	ex.printStackTrace(System.err);
943
		  	this.errno = ProtoCommon.ECONNREFUSED;
944
		  	return false;
945
			}
946
			
947
			try
948
			{
949
				if (!this.deleteStorage(trackerServer, groupName, storageIpAddr))
950
				{
951
					if (this.errno != 0)
952
					{
953
						if (this.errno == ProtoCommon.ERR_NO_ENOENT)
954
						{
955
							notFoundCount++;
956
						}
957
						else if (this.errno != ProtoCommon.ERR_NO_EALREADY)
958
						{
959
							return false;
960
						}
961
					}
962
				}
963
			}
964
			finally
965
			{
966
				try
967
				{
968
					trackerServer.close();
969
				}
970
				catch(IOException ex1)
971
				{
972
					ex1.printStackTrace();
973
				}
974
			}
975
		}
976
		
977
		if (notFoundCount == trackerGroup.tracker_servers.length)
978
		{
979
	  	this.errno = ProtoCommon.ERR_NO_ENOENT;
980
	  	return false;
981
		}
982
		
983
		if (this.errno == ProtoCommon.ERR_NO_ENOENT)
984
		{
985
			this.errno = 0;
986
		}
987
		
988
		return this.errno == 0;
989
	}
990
}

+ 120 - 0
src/main/java/org/csource/fastdfs/TrackerGroup.java

@ -0,0 +1,120 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.net.InetSocketAddress;
13
import java.net.Socket;
14
15
/**
16
* Tracker server group
17
* @author Happy Fish / YuQing
18
* @version Version 1.17
19
*/
20
public class TrackerGroup
21
{
22
	protected Integer lock;
23
	public int tracker_server_index;
24
	public InetSocketAddress[] tracker_servers;
25
	
26
/**
27
* Constructor
28
* @param tracker_servers tracker servers
29
*/
30
	public TrackerGroup(InetSocketAddress[] tracker_servers)
31
	{
32
		this.tracker_servers = tracker_servers;
33
		this.lock = new Integer(0);
34
		this.tracker_server_index = 0;
35
	}
36
37
/**
38
* return connected tracker server
39
* @return connected tracker server, null for fail
40
*/
41
	public TrackerServer getConnection(int serverIndex) throws IOException
42
	{
43
		Socket sock = new Socket();
44
		sock.setReuseAddress(true);
45
		sock.setSoTimeout(ClientGlobal.g_network_timeout);
46
		sock.connect(this.tracker_servers[serverIndex], ClientGlobal.g_connect_timeout);
47
		return new TrackerServer(sock, this.tracker_servers[serverIndex]);
48
	}
49
	
50
/**
51
* return connected tracker server
52
* @return connected tracker server, null for fail
53
*/
54
	public TrackerServer getConnection() throws IOException
55
	{
56
		int current_index;
57
		
58
		synchronized(this.lock)
59
		{
60
			this.tracker_server_index++;
61
			if (this.tracker_server_index >= this.tracker_servers.length)
62
			{
63
				this.tracker_server_index = 0;
64
			}
65
			
66
			current_index = this.tracker_server_index;
67
		}
68
		
69
		try
70
		{
71
			return this.getConnection(current_index);
72
	  }
73
	  catch(IOException ex)
74
	  {
75
	  	System.err.println("connect to server " + this.tracker_servers[current_index].getAddress().getHostAddress() + ":" + this.tracker_servers[current_index].getPort() + " fail");
76
	  	ex.printStackTrace(System.err);
77
	  }
78
	  
79
	  for (int i=0; i<this.tracker_servers.length; i++)
80
	  {
81
	  	if (i == current_index)
82
	  	{
83
	  		continue;
84
	  	}
85
	  	
86
			try
87
			{
88
				TrackerServer trackerServer = this.getConnection(i);
89
				
90
				synchronized(this.lock)
91
				{
92
					if (this.tracker_server_index == current_index)
93
					{
94
						this.tracker_server_index = i;
95
					}
96
				}
97
				
98
				return trackerServer;
99
		  }
100
		  catch(IOException ex)
101
		  {
102
		  	System.err.println("connect to server " + this.tracker_servers[i].getAddress().getHostAddress() + ":" + this.tracker_servers[i].getPort() + " fail");
103
		  	ex.printStackTrace(System.err);
104
		  }
105
	  }
106
	  
107
	  return null;
108
	}
109
110
	public Object clone()
111
	{
112
		InetSocketAddress[] trackerServers = new InetSocketAddress[this.tracker_servers.length];
113
		for (int i=0; i<trackerServers.length; i++)
114
		{
115
			trackerServers[i] = new InetSocketAddress(this.tracker_servers[i].getAddress().getHostAddress(), this.tracker_servers[i].getPort());
116
		}
117
		
118
		return new TrackerGroup(trackerServers);
119
	}
120
}

+ 90 - 0
src/main/java/org/csource/fastdfs/TrackerServer.java

@ -0,0 +1,90 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.io.InputStream;
13
import java.io.OutputStream;
14
import java.net.InetSocketAddress;
15
import java.net.Socket;
16
17
/**
18
* Tracker Server Info
19
* @author Happy Fish / YuQing
20
* @version Version 1.11
21
*/
22
public class TrackerServer
23
{
24
	protected Socket sock;
25
	protected InetSocketAddress inetSockAddr;
26
	
27
/**
28
* Constructor
29
* @param sock Socket of server
30
* @param inetSockAddr the server info
31
*/
32
	public TrackerServer(Socket sock, InetSocketAddress inetSockAddr)
33
	{
34
		this.sock = sock;
35
		this.inetSockAddr = inetSockAddr;
36
	}
37
	
38
/**
39
* get the connected socket
40
* @return the socket
41
*/
42
	public Socket getSocket() throws IOException
43
	{
44
		if (this.sock == null)
45
		{
46
			this.sock = ClientGlobal.getSocket(this.inetSockAddr);
47
		}
48
		
49
		return this.sock;
50
	}
51
	
52
/**
53
* get the server info
54
* @return the server info
55
*/
56
	public InetSocketAddress getInetSocketAddress()
57
	{
58
		return this.inetSockAddr;
59
	}
60
	
61
	public OutputStream getOutputStream() throws IOException
62
	{
63
		return this.sock.getOutputStream();
64
	}
65
	
66
	public InputStream getInputStream() throws IOException
67
	{
68
		return this.sock.getInputStream();
69
	}
70
71
	public void close() throws IOException
72
	{
73
		if (this.sock != null)
74
		{
75
			try
76
			{
77
				ProtoCommon.closeSocket(this.sock);
78
			}
79
			finally
80
			{
81
				this.sock = null;
82
			}
83
		}
84
	}
85
	
86
	protected void finalize() throws Throwable
87
	{
88
		this.close();
89
	}
90
}

+ 27 - 0
src/main/java/org/csource/fastdfs/UploadCallback.java

@ -0,0 +1,27 @@
1
/**
2
* Copyright (C) 2008 Happy Fish / YuQing
3
*
4
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
5
* General Public License (LGPL).
6
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
7
*/
8
9
package org.csource.fastdfs;
10
11
import java.io.IOException;
12
import java.io.OutputStream;
13
14
/**
15
* upload file callback interface
16
* @author Happy Fish / YuQing
17
* @version Version 1.0
18
*/
19
public interface UploadCallback
20
{
21
	/**
22
	* send file content callback function, be called only once when the file uploaded
23
	* @param out output stream for writing file content
24
	* @return 0 success, return none zero(errno) if fail
25
	*/
26
	public int send(OutputStream out) throws IOException;
27
}

+ 60 - 0
src/main/java/org/csource/fastdfs/UploadStream.java

@ -0,0 +1,60 @@
1
package org.csource.fastdfs;
2
3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.io.OutputStream;
6
7
/**
8
* Upload file by stream
9
* @author zhouzezhong & Happy Fish / YuQing
10
* @version Version 1.11
11
*/
12
public class UploadStream implements UploadCallback
13
{
14
	private InputStream inputStream; //input stream for reading
15
	private long fileSize = 0;  //size of the uploaded file
16
	
17
	/** 
18
	* constructor
19
	* @param inputStream input stream for uploading
20
	* @param fileSize size of uploaded file
21
	*/
22
	public UploadStream(InputStream inputStream, long fileSize)
23
	{
24
		super();
25
		this.inputStream = inputStream;
26
		this.fileSize = fileSize;
27
	}
28
29
	/**
30
	* send file content callback function, be called only once when the file uploaded
31
	* @param out output stream for writing file content
32
	* @return 0 success, return none zero(errno) if fail
33
	*/
34
	public int send(OutputStream out) throws IOException
35
	{
36
		long remainBytes = fileSize;
37
		byte[] buff = new byte[256 * 1024];
38
		int bytes;
39
		while(remainBytes > 0)
40
		{ 
41
			try
42
			{
43
				if ((bytes=inputStream.read(buff, 0, remainBytes > buff.length ? buff.length : (int)remainBytes)) < 0)
44
				{
45
					return -1;
46
				}
47
			}
48
			catch(IOException ex)
49
			{
50
				ex.printStackTrace(); 
51
				return -1;
52
			}
53
			
54
			out.write(buff, 0, bytes);
55
			remainBytes -= bytes;
56
		}
57
		
58
		return 0;
59
	}
60
}

+ 10 - 0
src/main/resources/application-dev.yml

@ -16,3 +16,13 @@ spring:
16 16
        testOnReturn: false
17 17
        poolPreparedStatements: true
18 18
        maxPoolPreparedStatementPerConnectionSize: 20
19
# FastDFS 服务配置
20
fdfs:
21
    network-timeout: 5
22
    connect-timeout: 30
23
    tracker-server:
24
        - 177.77.77.159:22122
25
    charset: UTF-8
26
    tracker-http-port: 8080
27
    anti-steal-token: false
28
    secret-key: FastDFS1234567890

+ 11 - 1
src/main/resources/application-pro.yml

@ -15,4 +15,14 @@ spring:
15 15
        testOnBorrow: false
16 16
        testOnReturn: false
17 17
        poolPreparedStatements: true
18
        maxPoolPreparedStatementPerConnectionSize: 20
18
        maxPoolPreparedStatementPerConnectionSize: 20
19
# FastDFS 服务配置
20
fdfs:
21
    network-timeout: 5
22
    connect-timeout: 30
23
    tracker-server:
24
        - 177.77.77.159:22122
25
    charset: UTF-8
26
    tracker-http-port: 8080
27
    anti-steal-token: false
28
    secret-key: FastDFS1234567890

+ 11 - 1
src/main/resources/application-test.yml

@ -15,4 +15,14 @@ spring:
15 15
        testOnBorrow: false
16 16
        testOnReturn: false
17 17
        poolPreparedStatements: true
18
        maxPoolPreparedStatementPerConnectionSize: 20
18
        maxPoolPreparedStatementPerConnectionSize: 20
19
# FastDFS 服务配置
20
fdfs:
21
    network-timeout: 5
22
    connect-timeout: 30
23
    tracker-server:
24
        - 177.77.77.159:22122
25
    charset: UTF-8
26
    tracker-http-port: 8080
27
    anti-steal-token: false
28
    secret-key: FastDFS1234567890