~smaioli/azureus/ubuntu-experimental

« back to all changes in this revision

Viewing changes to com/aelitis/azureus/core/devices/impl/DeviceImpl.java

MergedĀ VuzeĀ 4.2.0.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Created on Jan 28, 2009
 
3
 * Created by Paul Gardner
 
4
 * 
 
5
 * Copyright 2009 Vuze, Inc.  All rights reserved.
 
6
 * 
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; version 2 of the License only.
 
10
 * 
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
14
 * GNU General Public License for more details.
 
15
 * 
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
 
 
22
package com.aelitis.azureus.core.devices.impl;
 
23
 
 
24
import java.io.File;
 
25
import java.io.IOException;
 
26
import java.lang.ref.WeakReference;
 
27
import java.lang.reflect.Constructor;
 
28
import java.net.URL;
 
29
import java.text.SimpleDateFormat;
 
30
import java.util.*;
 
31
 
 
32
import org.gudy.azureus2.core3.config.COConfigurationManager;
 
33
import org.gudy.azureus2.core3.internat.MessageText;
 
34
import org.gudy.azureus2.core3.util.AERunnable;
 
35
import org.gudy.azureus2.core3.util.ByteFormatter;
 
36
import org.gudy.azureus2.core3.util.Debug;
 
37
import org.gudy.azureus2.core3.util.DelayedEvent;
 
38
import org.gudy.azureus2.core3.util.FileUtil;
 
39
import org.gudy.azureus2.core3.util.IndentWriter;
 
40
import org.gudy.azureus2.core3.util.LightHashMap;
 
41
import org.gudy.azureus2.core3.util.SystemProperties;
 
42
import org.gudy.azureus2.core3.util.SystemTime;
 
43
import org.gudy.azureus2.plugins.disk.DiskManagerFileInfo;
 
44
 
 
45
import com.aelitis.azureus.core.devices.Device;
 
46
import com.aelitis.azureus.core.devices.DeviceMediaRenderer;
 
47
import com.aelitis.azureus.core.devices.TranscodeException;
 
48
import com.aelitis.azureus.core.devices.TranscodeFile;
 
49
import com.aelitis.azureus.core.devices.TranscodeProfile;
 
50
import com.aelitis.azureus.core.devices.TranscodeProvider;
 
51
import com.aelitis.azureus.core.devices.TranscodeTarget;
 
52
import com.aelitis.azureus.core.devices.TranscodeTargetListener;
 
53
import com.aelitis.azureus.core.util.CopyOnWriteList;
 
54
import com.aelitis.azureus.util.ImportExportUtils;
 
55
 
 
56
public abstract class 
 
57
DeviceImpl
 
58
        implements Device
 
59
{
 
60
        private static final String MY_PACKAGE = "com.aelitis.azureus.core.devices.impl";
 
61
        
 
62
        protected static DeviceImpl
 
63
        importFromBEncodedMapStatic(
 
64
                DeviceManagerImpl       manager,
 
65
                Map                                     map )
 
66
        
 
67
                throws IOException
 
68
        {
 
69
                String  impl = ImportExportUtils.importString( map, "_impl" );
 
70
                
 
71
                if ( impl.startsWith( "." )){
 
72
                        
 
73
                        impl = MY_PACKAGE + impl;
 
74
                }
 
75
                
 
76
                try{
 
77
                        Class<DeviceImpl> cla = (Class<DeviceImpl>) Class.forName( impl );
 
78
                        
 
79
                        Constructor<DeviceImpl> cons = cla.getDeclaredConstructor( DeviceManagerImpl.class, Map.class );
 
80
                        
 
81
                        cons.setAccessible( true );
 
82
                        
 
83
                        return( cons.newInstance( manager, map ));
 
84
                        
 
85
                }catch( Throwable e ){
 
86
 
 
87
                        Debug.out( "Can't construct device for " + impl, e );
 
88
                        
 
89
                        throw( new IOException( "Construction failed: " + Debug.getNestedExceptionMessage(e)));
 
90
                }
 
91
        }
 
92
        
 
93
        private static final String PP_REND_WORK_DIR            = "tt_work_dir"; 
 
94
        private static final String PP_REND_DEF_TRANS_PROF      = "tt_def_trans_prof";
 
95
        private static final String PP_REND_TRANS_REQ           = "tt_req";
 
96
        private static final String PP_REND_TRANS_CACHE         = "tt_always_cache";
 
97
        
 
98
        protected static final String   PP_IP_ADDRESS           = "rend_ip";    
 
99
        protected static final String   TP_IP_ADDRESS           = "DeviceUPnPImpl:ip";  // transient
 
100
        protected static final String   PP_FILTER_FILES         = "rend_filter";
 
101
        
 
102
        protected static final String   PP_COPY_OUTSTANDING = "copy_outstanding";
 
103
        protected static final String   PP_AUTO_START           = "auto_start";
 
104
 
 
105
        protected static final boolean  PR_AUTO_START_DEFAULT   = true;
 
106
        
 
107
        private static final String     GENERIC = "generic";
 
108
        
 
109
        
 
110
        private DeviceManagerImpl       manager;
 
111
        private int                                     type;
 
112
        private String                          uid;
 
113
        private String                          secondary_uid;
 
114
        private String                          name;
 
115
        private boolean                         manual;
 
116
        
 
117
        private boolean                 hidden;
 
118
        private long                    last_seen;
 
119
        
 
120
        private boolean                 online;
 
121
        
 
122
        private boolean                 transcoding;
 
123
        
 
124
        private Map<String,Object>      persistent_properties   = new LightHashMap<String, Object>(1);
 
125
 
 
126
        private Map<Object,Object>      transient_properties    = new LightHashMap<Object, Object>(1);
 
127
        
 
128
        private long                                            device_files_last_mod;
 
129
        private boolean                                         device_files_dirty;
 
130
        private Map<String,Map<String,?>>       device_files;
 
131
        
 
132
        private WeakReference<Map<String,Map<String,?>>> device_files_ref;
 
133
        
 
134
        private CopyOnWriteList<TranscodeTargetListener>        listeners = new CopyOnWriteList<TranscodeTargetListener>();
 
135
        
 
136
        private Map<Object,String>      errors  = new HashMap<Object, String>();
 
137
        private Map<Object,String>      infos   = new HashMap<Object, String>();
 
138
        
 
139
        protected
 
140
        DeviceImpl(
 
141
                DeviceManagerImpl       _manager,
 
142
                int                                     _type,
 
143
                String                          _uid,
 
144
                String                          _name,
 
145
                boolean                         _manual )
 
146
        {
 
147
                manager         = _manager;
 
148
                type            = _type;
 
149
                uid                     = _uid;
 
150
                name            = _name;
 
151
                manual          = _manual;
 
152
        }
 
153
        
 
154
        protected
 
155
        DeviceImpl(
 
156
                DeviceManagerImpl       _manager,
 
157
                Map                                     map )
 
158
        
 
159
                throws IOException
 
160
        {
 
161
                manager = _manager;
 
162
                
 
163
                type    = (int)ImportExportUtils.importLong( map, "_type" );
 
164
                uid             = ImportExportUtils.importString( map, "_uid" );
 
165
                name    = ImportExportUtils.importString( map, "_name" );
 
166
                
 
167
                secondary_uid           = ImportExportUtils.importString( map, "_suid" );
 
168
 
 
169
                last_seen       = ImportExportUtils.importLong( map, "_ls" );
 
170
                hidden          = ImportExportUtils.importBoolean( map, "_hide" );      
 
171
                manual          = ImportExportUtils.importBoolean( map, "_man" );
 
172
 
 
173
                if ( map.containsKey( "_pprops" )){
 
174
                        
 
175
                        persistent_properties = (Map<String,Object>)map.get( "_pprops" );
 
176
                }
 
177
        }
 
178
        
 
179
        protected void
 
180
        exportToBEncodedMap(
 
181
                Map                                     map )
 
182
        
 
183
                throws IOException
 
184
        {
 
185
                String  cla = this.getClass().getName();
 
186
                
 
187
                if ( cla.startsWith( MY_PACKAGE )){
 
188
                        
 
189
                        cla = cla.substring( MY_PACKAGE.length());
 
190
                }
 
191
                
 
192
                ImportExportUtils.exportString( map, "_impl", cla );
 
193
                ImportExportUtils.exportLong( map, "_type", new Long( type ));
 
194
                ImportExportUtils.exportString( map, "_uid", uid );
 
195
                ImportExportUtils.exportString( map, "_name", name );
 
196
                
 
197
                if ( secondary_uid != null ){
 
198
                        
 
199
                        ImportExportUtils.exportString( map, "_suid", secondary_uid );
 
200
                }
 
201
                
 
202
                ImportExportUtils.exportLong( map, "_ls", new Long( last_seen ));
 
203
                ImportExportUtils.exportBoolean( map, "_hide", hidden );
 
204
                ImportExportUtils.exportBoolean( map, "_man", manual );
 
205
                
 
206
                map.put( "_pprops", persistent_properties );
 
207
        }
 
208
        
 
209
        protected boolean
 
210
        updateFrom(
 
211
                DeviceImpl              other )
 
212
        {
 
213
                if ( type != other.type ){
 
214
                        
 
215
                        Debug.out( "Inconsistent update operation (type)" );
 
216
                        
 
217
                        return( false );                        
 
218
                }
 
219
                
 
220
                String  o_uid   = other.uid;
 
221
                String  o_suid  = other.secondary_uid;
 
222
                
 
223
                if ( !uid.equals( o_uid )){
 
224
                        
 
225
                        boolean borked = false;
 
226
                        
 
227
                        if ( secondary_uid == null && o_suid == null ){
 
228
                        
 
229
                                borked = true;
 
230
                        
 
231
                        }else if (      secondary_uid == null && uid.equals( o_suid ) ||
 
232
                                                o_suid == null && o_uid.equals( secondary_uid ) ||
 
233
                                                o_suid.equals( secondary_uid )){
 
234
                                
 
235
                        }else{
 
236
                                
 
237
                                borked = true;
 
238
                        }
 
239
                        
 
240
                        if ( borked ){
 
241
                                
 
242
                                Debug.out( "Inconsistent update operation (uids)" );
 
243
                                
 
244
                                return( false );
 
245
 
 
246
                        }
 
247
                }
 
248
                
 
249
                if ( !name.equals( other.name )){
 
250
                        
 
251
                        name    = other.name;
 
252
                        
 
253
                        setDirty();
 
254
                }
 
255
                
 
256
                if ( manual != other.manual ){
 
257
                        
 
258
                        manual  = other.manual;
 
259
                        
 
260
                        setDirty();
 
261
                }
 
262
                
 
263
                alive();
 
264
                
 
265
                return( true );
 
266
        }
 
267
        
 
268
        protected void
 
269
        initialise()
 
270
        {
 
271
                updateStatus( 0 );
 
272
        }
 
273
        
 
274
        protected void
 
275
        destroy()
 
276
        {       
 
277
        }
 
278
        
 
279
        public int
 
280
        getType()
 
281
        {
 
282
                return( type );
 
283
        }
 
284
        
 
285
        public String
 
286
        getID()
 
287
        {
 
288
                return( uid );
 
289
        }
 
290
        
 
291
        protected void
 
292
        setSecondaryID(
 
293
                String          str )
 
294
        {
 
295
                secondary_uid = str;
 
296
        }
 
297
        
 
298
        protected String
 
299
        getSecondaryID()
 
300
        {
 
301
                return( secondary_uid );
 
302
        }
 
303
        
 
304
        public Device
 
305
        getDevice()
 
306
        {
 
307
                return( this );
 
308
        }
 
309
 
 
310
        public String
 
311
        getName()
 
312
        {
 
313
                return( name );
 
314
        }
 
315
        
 
316
        public String
 
317
        getShortDescription()
 
318
        {
 
319
                if ( getRendererSpecies() == DeviceMediaRenderer.RS_ITUNES ){
 
320
                        
 
321
                        return( "iPhone, iPod, Apple TV" );
 
322
                }
 
323
                
 
324
                return( null );
 
325
        }
 
326
        
 
327
        public int
 
328
        getRendererSpecies()
 
329
        {
 
330
                        // note, overridden in itunes
 
331
                
 
332
                if ( name.equalsIgnoreCase( "PS3" )){
 
333
                        
 
334
                        return( DeviceMediaRenderer.RS_PS3 );
 
335
                        
 
336
                }else if ( name.equalsIgnoreCase( "XBox 360" )){
 
337
                        
 
338
                        return( DeviceMediaRenderer.RS_XBOX );
 
339
                
 
340
                }else if ( name.equalsIgnoreCase( "Wii" )){
 
341
 
 
342
                        return( DeviceMediaRenderer.RS_WII );
 
343
                        
 
344
                }else if ( name.equalsIgnoreCase( "Browser" )){
 
345
 
 
346
                        return( DeviceMediaRenderer.RS_BROWSER );
 
347
                        
 
348
                }else{
 
349
                        
 
350
                        return( DeviceMediaRenderer.RS_OTHER );
 
351
                }       
 
352
        }
 
353
        
 
354
        protected String
 
355
        getDeviceClassification()
 
356
        {
 
357
                        // note, overridden in itunes
 
358
                
 
359
                switch( getRendererSpecies()){
 
360
                
 
361
                        case DeviceMediaRenderer.RS_PS3:{
 
362
                                
 
363
                                return( "sony.PS3" );
 
364
                        }
 
365
                        case DeviceMediaRenderer.RS_XBOX:{
 
366
                                
 
367
                                return( "microsoft.XBox" );
 
368
                        }
 
369
                        case DeviceMediaRenderer.RS_WII:{
 
370
                                
 
371
                                return( "nintendo.Wii" );
 
372
                        }
 
373
                        case DeviceMediaRenderer.RS_BROWSER:{
 
374
                                
 
375
                                return( "browser.generic" );
 
376
                        }
 
377
                        case DeviceMediaRenderer.RS_OTHER:{
 
378
                                
 
379
                                return( GENERIC );
 
380
                        }
 
381
                        default:{
 
382
                                Debug.out( "Unknown classification" );
 
383
                                
 
384
                                return( GENERIC );
 
385
                        }
 
386
                }
 
387
        }
 
388
        
 
389
        public boolean
 
390
        isGeneric()
 
391
        {
 
392
                return( getDeviceClassification() == GENERIC );
 
393
        }
 
394
        
 
395
        public boolean
 
396
        isManual()
 
397
        {
 
398
                return( manual );
 
399
        }
 
400
        
 
401
        public boolean
 
402
        isHidden()
 
403
        {
 
404
                return( hidden );
 
405
        }
 
406
        
 
407
        public void
 
408
        setHidden(
 
409
                boolean         h )
 
410
        {
 
411
                if ( h != hidden ){
 
412
                        
 
413
                        hidden  = h;
 
414
                        
 
415
                        setDirty();
 
416
                }
 
417
        }
 
418
        
 
419
        protected void
 
420
        alive()
 
421
        {
 
422
                if ( !manual ){
 
423
                        
 
424
                        last_seen       = SystemTime.getCurrentTime();
 
425
                        
 
426
                        online  = true;
 
427
                        
 
428
                        setDirty( false );
 
429
                }
 
430
        }
 
431
        
 
432
        public boolean
 
433
        isAlive()
 
434
        {
 
435
                return( online );
 
436
        }
 
437
        
 
438
        protected void
 
439
        dead()
 
440
        {
 
441
                if ( !manual ){
 
442
                        
 
443
                        online  = false;
 
444
                        
 
445
                        setDirty( false );
 
446
                }
 
447
        }
 
448
        
 
449
        protected void
 
450
        setDirty()
 
451
        {
 
452
                setDirty( true );
 
453
        }
 
454
        
 
455
        protected void
 
456
        setDirty(
 
457
                boolean         save_changes )
 
458
        {
 
459
                manager.configDirty( this, save_changes );
 
460
        }
 
461
        
 
462
        protected void
 
463
        updateStatus(
 
464
                int             tick_count )
 
465
        {       
 
466
        }
 
467
        
 
468
        public void 
 
469
        requestAttention() 
 
470
        {
 
471
                manager.requestAttention( this );
 
472
        }
 
473
        
 
474
        public TranscodeFileImpl[]
 
475
        getFiles()
 
476
        {
 
477
                try{
 
478
                        synchronized( this ){
 
479
                                
 
480
                                if ( device_files == null ){
 
481
                                        
 
482
                                        loadDeviceFile();
 
483
                                }
 
484
                                
 
485
                                List<TranscodeFile> result = new ArrayList<TranscodeFile>();
 
486
                                                                
 
487
                                Iterator<Map.Entry<String,Map<String,?>>> it = device_files.entrySet().iterator();
 
488
                                        
 
489
                                while( it.hasNext()){
 
490
                                        
 
491
                                        Map.Entry<String,Map<String,?>> entry = it.next();
 
492
                                        
 
493
                                        try{
 
494
                                                TranscodeFileImpl tf = new TranscodeFileImpl( this, entry.getKey(), device_files );
 
495
                                                
 
496
                                                result.add( tf );
 
497
                                                
 
498
                                        }catch( Throwable e ){
 
499
                                                
 
500
                                                it.remove();
 
501
                                                
 
502
                                                log( "Failed to deserialise transcode file", e );
 
503
                                        }
 
504
                                }
 
505
                                
 
506
                                return( result.toArray( new TranscodeFileImpl[ result.size() ]));
 
507
                        }
 
508
                }catch( Throwable e ){
 
509
                        
 
510
                        Debug.out( e );
 
511
                        
 
512
                        return( new TranscodeFileImpl[0] );
 
513
                }
 
514
        }
 
515
        
 
516
        public TranscodeFileImpl
 
517
        allocateFile(
 
518
                TranscodeProfile                profile,
 
519
                boolean                                 no_xcode,
 
520
                DiskManagerFileInfo             file,
 
521
                boolean                                 for_job )
 
522
        
 
523
                throws TranscodeException
 
524
        {
 
525
                TranscodeFileImpl       result = null;
 
526
                
 
527
                try{
 
528
                        synchronized( this ){
 
529
                                
 
530
                                if ( device_files == null ){
 
531
                                        
 
532
                                        loadDeviceFile();
 
533
                                }
 
534
        
 
535
                                String  key = ByteFormatter.encodeString( file.getDownloadHash() ) + ":" + file.getIndex() + ":" + profile.getUID();
 
536
                                                                
 
537
                                if ( device_files.containsKey( key )){
 
538
                                
 
539
                                        try{                                    
 
540
                                                result = new TranscodeFileImpl( this, key, device_files );
 
541
                                                
 
542
                                        }catch( Throwable e ){
 
543
                                                
 
544
                                                device_files.remove( key );
 
545
                                                
 
546
                                                log( "Failed to deserialise transcode file", e );
 
547
                                        }
 
548
                                }
 
549
                                
 
550
                                if ( result == null ){
 
551
                                                        
 
552
                                        String ext = profile.getFileExtension();
 
553
                                        
 
554
                                        String  target_file = file.getFile().getName();
 
555
                                        
 
556
                                        if ( ext != null && !no_xcode ){
 
557
                                                
 
558
                                                int     pos = target_file.lastIndexOf( '.' );
 
559
                                                
 
560
                                                if ( pos != -1 ){
 
561
                                                        
 
562
                                                        target_file = target_file.substring( 0, pos ); 
 
563
                                                }
 
564
                                                
 
565
                                                target_file += ext;
 
566
                                        }
 
567
                                                
 
568
                                        target_file = allocateUniqueFileName( target_file );
 
569
                                        
 
570
                                        File output_file = getWorkingDirectory();
 
571
        
 
572
                                        output_file = new File( output_file.getAbsoluteFile(), target_file );
 
573
        
 
574
                                        result = new TranscodeFileImpl( this, key, profile.getName(), device_files, output_file, for_job );
 
575
                                                        
 
576
                                        result.setSourceFile( file );
 
577
                                        
 
578
                                        saveDeviceFile();
 
579
                                        
 
580
                                }else{
 
581
                                        
 
582
                                        result.setSourceFile( file );
 
583
                                        
 
584
                                        result.setProfileName( profile.getName());
 
585
                                }
 
586
                        }
 
587
                }catch( Throwable e ){
 
588
                        
 
589
                        throw( new TranscodeException( "File allocation failed", e ));
 
590
                }
 
591
                
 
592
                for ( TranscodeTargetListener l: listeners ){
 
593
                        
 
594
                        try{
 
595
                                l.fileAdded( result );
 
596
                                
 
597
                        }catch( Throwable e ){
 
598
                                
 
599
                                Debug.out( e );
 
600
                        }
 
601
                }
 
602
                
 
603
                return( result );
 
604
        }
 
605
        
 
606
        protected String
 
607
        allocateUniqueFileName(
 
608
                String          str )
 
609
        {
 
610
                Set<String> name_set = new HashSet<String>();
 
611
                
 
612
                for (Map<String,?> entry: device_files.values()){
 
613
                        
 
614
                        try{
 
615
                                name_set.add( new File( ImportExportUtils.importString( entry, TranscodeFileImpl.KEY_FILE )).getName());
 
616
                                
 
617
                        }catch( Throwable e ){
 
618
                                
 
619
                                Debug.out( e );
 
620
                        }
 
621
                }
 
622
 
 
623
                for (int i=0;i<1024;i++){
 
624
                        
 
625
                        String  test_name = i==0?str:( i + "_" + str);
 
626
                        
 
627
                        if ( !name_set.contains( test_name )){
 
628
                        
 
629
                                str = test_name;
 
630
                                
 
631
                                break;
 
632
                        }                               
 
633
                }
 
634
                
 
635
                return( str );
 
636
        }
 
637
        
 
638
        protected void
 
639
        revertFileName(
 
640
                TranscodeFileImpl       tf )
 
641
        
 
642
                throws TranscodeException
 
643
        {
 
644
                File cache_file = tf.getCacheFile();
 
645
                
 
646
                if ( cache_file.exists()){
 
647
                        
 
648
                        Debug.out( "Cache file already allocated, can't rename" );
 
649
                        
 
650
                        return;
 
651
                }
 
652
                
 
653
                File source_file = tf.getSourceFile().getFile();
 
654
                
 
655
                String  original_name = source_file.getName();
 
656
                
 
657
                int pos = original_name.indexOf('.');
 
658
                
 
659
                if ( pos == -1 ){
 
660
                        
 
661
                        return;
 
662
                }
 
663
                
 
664
                String  cf_name = cache_file.getName();
 
665
                
 
666
                if ( cf_name.endsWith( original_name.substring(pos))){
 
667
                        
 
668
                        return;
 
669
                }
 
670
                
 
671
                try{
 
672
                        synchronized( this ){
 
673
                                
 
674
                                if ( device_files == null ){
 
675
                                        
 
676
                                        loadDeviceFile();
 
677
                                }
 
678
                                
 
679
                                String reverted_name = allocateUniqueFileName( original_name );
 
680
                                
 
681
                                tf.setCacheFile( new File( cache_file.getParentFile(), reverted_name ));
 
682
                        }
 
683
                }catch( Throwable e ){
 
684
                        
 
685
                        throw( new TranscodeException( "File name revertion failed", e ));
 
686
                }
 
687
        }
 
688
        
 
689
        public TranscodeFileImpl
 
690
        lookupFile(
 
691
                TranscodeProfile                profile,
 
692
                DiskManagerFileInfo             file )
 
693
        {
 
694
                try{
 
695
                        synchronized( this ){
 
696
                                
 
697
                                if ( device_files == null ){
 
698
                                        
 
699
                                        loadDeviceFile();
 
700
                                }
 
701
        
 
702
                                String  key = ByteFormatter.encodeString( file.getDownloadHash() ) + ":" + file.getIndex() + ":" + profile.getUID();
 
703
                                                                
 
704
                                if ( device_files.containsKey( key )){
 
705
                                
 
706
                                        try{                                    
 
707
                                                return( new TranscodeFileImpl( this, key, device_files ));
 
708
                                                
 
709
                                        }catch( Throwable e ){
 
710
                                                
 
711
                                                device_files.remove( key );
 
712
                                                
 
713
                                                log( "Failed to deserialise transcode file", e );
 
714
                                        }
 
715
                                }
 
716
                        }
 
717
                }catch( Throwable e ){
 
718
                }
 
719
                
 
720
                return( null );
 
721
        }
 
722
        
 
723
        protected TranscodeFileImpl
 
724
        getTranscodeFile(
 
725
                String          key )
 
726
        {
 
727
                try{
 
728
                        synchronized( this ){
 
729
                                
 
730
                                if ( device_files == null ){
 
731
                                        
 
732
                                        loadDeviceFile();
 
733
                                }
 
734
                                                                        
 
735
                                if ( device_files.containsKey( key )){
 
736
                                
 
737
                                        try{                                    
 
738
 
 
739
                                                return( new TranscodeFileImpl( this, key, device_files ));
 
740
                                                
 
741
                                }       catch( Throwable e ){
 
742
                                                
 
743
                                                device_files.remove( key );
 
744
                                                
 
745
                                                log( "Failed to deserialise transcode file", e );
 
746
                                        }
 
747
                                }
 
748
                        }
 
749
                }catch( Throwable e ){
 
750
                }
 
751
                
 
752
                return( null );
 
753
        }
 
754
        
 
755
        public File
 
756
        getWorkingDirectory()
 
757
        {                               
 
758
                String result = getPersistentStringProperty( PP_REND_WORK_DIR );
 
759
                
 
760
                if ( result.length() == 0 ){
 
761
                        
 
762
                        String  def_dir = COConfigurationManager.getStringParameter( "Default save path" );
 
763
 
 
764
                        File f = new File( def_dir, "transcodes" );
 
765
                        
 
766
                        f.mkdirs();
 
767
                        
 
768
                        String  name = FileUtil.convertOSSpecificChars( getName(), true );
 
769
                        
 
770
                        for (int i=0;i<1024;i++){
 
771
                                
 
772
                                String test_name = name + (i==0?"":("_"+i));
 
773
                                
 
774
                                File test_file = new File( f, test_name );
 
775
                                
 
776
                                if ( !test_file.exists()){
 
777
                        
 
778
                                        f = test_file;
 
779
                                        
 
780
                                        break;
 
781
                                }
 
782
                        }
 
783
                        
 
784
                        result = f.getAbsolutePath();
 
785
                        
 
786
                        setPersistentStringProperty( PP_REND_WORK_DIR, result );
 
787
                }
 
788
                
 
789
                File f_result = new File( result );
 
790
                
 
791
                if ( !f_result.exists()){
 
792
                        
 
793
                        f_result.mkdirs();
 
794
                }
 
795
                
 
796
                return( f_result );
 
797
        }
 
798
        
 
799
        public void
 
800
        setWorkingDirectory(
 
801
                File            directory )
 
802
        {
 
803
                setPersistentStringProperty( PP_REND_WORK_DIR, directory.getAbsolutePath());
 
804
        }
 
805
 
 
806
        public TranscodeProfile[]
 
807
        getTranscodeProfiles()
 
808
        {               
 
809
                List<TranscodeProfile>  profiles = new ArrayList<TranscodeProfile>();
 
810
                
 
811
                DeviceManagerImpl dm = getManager();
 
812
                
 
813
                TranscodeManagerImpl tm = dm.getTranscodeManager();
 
814
                                
 
815
                TranscodeProvider[] providers = tm.getProviders();
 
816
                                
 
817
                String classification = getDeviceClassification();
 
818
                
 
819
                for ( TranscodeProvider provider: providers ){
 
820
                        
 
821
                        TranscodeProfile[] ps = provider.getProfiles();
 
822
                        
 
823
                        for ( TranscodeProfile p : ps ){
 
824
                                
 
825
                                String c = p.getDeviceClassification();
 
826
                                
 
827
                                if ( c == null ){
 
828
                                        
 
829
                                        log( "Device classification missing for " + p.getName());
 
830
                                        
 
831
                                }else{
 
832
                                        if ( c.toLowerCase().startsWith( classification.toLowerCase())){
 
833
                                                
 
834
                                                profiles.add( p );
 
835
                                        }
 
836
                                }
 
837
                        }
 
838
                }
 
839
                
 
840
                return( profiles.toArray( new TranscodeProfile[profiles.size()] ));
 
841
        }
 
842
                
 
843
        public TranscodeProfile
 
844
        getDefaultTranscodeProfile()
 
845
        {
 
846
                String uid = getPersistentStringProperty( PP_REND_DEF_TRANS_PROF );
 
847
                
 
848
                DeviceManagerImpl dm = getManager();
 
849
                
 
850
                TranscodeManagerImpl tm = dm.getTranscodeManager();
 
851
 
 
852
                TranscodeProfile profile = tm.getProfileFromUID( uid );
 
853
                
 
854
                if ( profile != null ){
 
855
                        
 
856
                        return( profile );
 
857
                }
 
858
        
 
859
                return( null );
 
860
        }
 
861
        
 
862
        public void
 
863
        setDefaultTranscodeProfile(
 
864
                TranscodeProfile                profile )
 
865
        {
 
866
                if ( profile == null ){
 
867
                
 
868
                        removePersistentProperty( PP_REND_DEF_TRANS_PROF );
 
869
                        
 
870
                }else{
 
871
                        
 
872
                        setPersistentStringProperty( PP_REND_DEF_TRANS_PROF, profile.getUID());
 
873
                }
 
874
        }
 
875
        
 
876
        protected void
 
877
        setTranscoding(
 
878
                boolean         _transcoding )
 
879
        {
 
880
                transcoding = _transcoding;
 
881
                
 
882
                manager.deviceChanged( this, false );
 
883
        }
 
884
        
 
885
        public boolean
 
886
        isTranscoding()
 
887
        {
 
888
                return( transcoding );
 
889
        }
 
890
        
 
891
        public int
 
892
        getTranscodeRequirement()
 
893
        {
 
894
                return( getPersistentIntProperty( PP_REND_TRANS_REQ, TranscodeTarget.TRANSCODE_WHEN_REQUIRED ));
 
895
        }
 
896
        
 
897
        public void
 
898
        setTranscodeRequirement(
 
899
                int             req )
 
900
        {
 
901
                setPersistentIntProperty( PP_REND_TRANS_REQ, req );
 
902
        }
 
903
        
 
904
        public boolean
 
905
        getAlwaysCacheFiles()
 
906
        {
 
907
                return( getPersistentBooleanProperty( PP_REND_TRANS_CACHE, false ));
 
908
        }
 
909
        
 
910
        public void
 
911
        setAlwaysCacheFiles(
 
912
                boolean         always_cache )
 
913
        {
 
914
                setPersistentBooleanProperty( PP_REND_TRANS_CACHE, always_cache );
 
915
        }
 
916
        
 
917
        public String[][] 
 
918
        getDisplayProperties() 
 
919
        {
 
920
                List<String[]> dp = new ArrayList<String[]>();
 
921
                
 
922
            getDisplayProperties( dp );
 
923
                    
 
924
            String[][] res = new String[2][dp.size()];
 
925
           
 
926
            int pos = 0;
 
927
            
 
928
            for ( String[] entry: dp ){
 
929
            
 
930
                res[0][pos] = entry[0];
 
931
                res[1][pos] = entry[1];
 
932
                
 
933
                pos++;
 
934
            }
 
935
            
 
936
            return( res );
 
937
        }
 
938
        
 
939
        protected void
 
940
        getDisplayProperties(
 
941
                List<String[]>  dp )
 
942
        {
 
943
                addDP( dp, "TableColumn.header.name", name );
 
944
                
 
945
                if ( !manual ){
 
946
                
 
947
                        addDP( dp, "azbuddy.ui.table.online",  online );
 
948
                
 
949
                        addDP( dp, "device.lastseen", last_seen==0?"":new SimpleDateFormat().format(new Date( last_seen )));
 
950
                }
 
951
        }
 
952
        
 
953
        protected void
 
954
        getTTDisplayProperties(
 
955
                List<String[]>  dp )
 
956
        {
 
957
                addDP( dp, "devices.xcode.working_dir", getWorkingDirectory().getAbsolutePath());
 
958
        
 
959
                addDP( dp, "devices.xcode.prof_def", getDefaultTranscodeProfile());
 
960
                
 
961
                addDP( dp, "devices.xcode.profs", getTranscodeProfiles());
 
962
                
 
963
                int     tran_req = getTranscodeRequirement();
 
964
                
 
965
                String  tran_req_str;
 
966
                
 
967
                if ( tran_req == TranscodeTarget.TRANSCODE_ALWAYS ){
 
968
                        
 
969
                         tran_req_str = "device.xcode.always";
 
970
                         
 
971
                }else if ( tran_req == TranscodeTarget.TRANSCODE_NEVER ){
 
972
                        
 
973
                         tran_req_str = "device.xcode.never";
 
974
                }else{
 
975
                        
 
976
                         tran_req_str = "device.xcode.whenreq";
 
977
                }
 
978
                
 
979
                addDP( dp, "device.xcode", MessageText.getString( tran_req_str ));
 
980
        }
 
981
        
 
982
        protected void
 
983
        addDP(
 
984
                List<String[]>  dp,
 
985
                String                  name,
 
986
                String                  value )
 
987
        {
 
988
                dp.add( new String[]{ name, value });
 
989
        }
 
990
        
 
991
        protected void
 
992
        addDP(
 
993
                List<String[]>  dp,
 
994
                String                  name,
 
995
                String[]                values )
 
996
        {
 
997
                String value = "";
 
998
                
 
999
                for ( String v: values ){
 
1000
                        
 
1001
                        value += (value.length()==0?"":",") + v;
 
1002
                }
 
1003
                
 
1004
                dp.add( new String[]{ name, value });
 
1005
        }
 
1006
        
 
1007
        protected void
 
1008
        addDP(
 
1009
                List<String[]>  dp,
 
1010
                String                  name,
 
1011
                boolean                 value )
 
1012
        {
 
1013
                dp.add( new String[]{ name, MessageText.getString( value?"GeneralView.yes":"GeneralView.no" ) });
 
1014
        }
 
1015
        
 
1016
        
 
1017
        protected void
 
1018
        addDP(
 
1019
                List<String[]>          dp,
 
1020
                String                          name,
 
1021
                TranscodeProfile        value )
 
1022
        {
 
1023
                addDP( dp, name, value==null?"":value.getName());
 
1024
        }
 
1025
        
 
1026
        protected void
 
1027
        addDP(
 
1028
                List<String[]>          dp,
 
1029
                String                          name,
 
1030
                TranscodeProfile[]      values )
 
1031
        {
 
1032
                String[]        names = new String[values.length];
 
1033
                
 
1034
                for (int i=0;i<values.length;i++){
 
1035
                        
 
1036
                        names[i] = values[i].getName();
 
1037
                }
 
1038
                
 
1039
                addDP( dp, name, names);
 
1040
        }
 
1041
        
 
1042
        public boolean
 
1043
        canRemove()
 
1044
        {
 
1045
                return( true );
 
1046
        }
 
1047
        
 
1048
        public void
 
1049
        remove()
 
1050
        {
 
1051
                manager.removeDevice( this );
 
1052
        }
 
1053
        
 
1054
        public String
 
1055
        getPersistentStringProperty(
 
1056
                String          prop )
 
1057
        {
 
1058
                return( getPersistentStringProperty( prop, "" ));
 
1059
        }
 
1060
        
 
1061
        public String
 
1062
        getPersistentStringProperty(
 
1063
                String          prop,
 
1064
                String          def )
 
1065
        {
 
1066
                synchronized( persistent_properties ){
 
1067
                        
 
1068
                        try{
 
1069
                                byte[]  value = (byte[])persistent_properties.get( prop );
 
1070
                
 
1071
                                if ( value == null ){
 
1072
                                        
 
1073
                                        return( def );
 
1074
                                }
 
1075
                                
 
1076
                                return( new String( value, "UTF-8" ));
 
1077
                                
 
1078
                        }catch( Throwable e ){
 
1079
                                
 
1080
                                Debug.printStackTrace(e);
 
1081
                                
 
1082
                                return( def );
 
1083
                        }
 
1084
                }
 
1085
        }
 
1086
        
 
1087
        public void
 
1088
        setPersistentStringProperty(
 
1089
                String          prop,
 
1090
                String          value )
 
1091
        {
 
1092
                boolean dirty = false;
 
1093
                
 
1094
                synchronized( persistent_properties ){
 
1095
                        
 
1096
                        String existing = getPersistentStringProperty( prop );
 
1097
                        
 
1098
                        if ( !existing.equals( value )){
 
1099
                                
 
1100
                                try{
 
1101
                                        persistent_properties.put( prop, value.getBytes( "UTF-8" ));
 
1102
                                        
 
1103
                                        dirty = true;
 
1104
                                        
 
1105
                                }catch( Throwable e ){
 
1106
                                        
 
1107
                                        Debug.printStackTrace(e);
 
1108
                                }
 
1109
                        }
 
1110
                }
 
1111
                
 
1112
                if ( dirty ){
 
1113
                        
 
1114
                        setDirty();
 
1115
                }
 
1116
        }
 
1117
        
 
1118
        public void
 
1119
        removePersistentProperty(
 
1120
                String          prop )
 
1121
        {
 
1122
                boolean dirty = false;
 
1123
                
 
1124
                synchronized( persistent_properties ){
 
1125
                        
 
1126
                        String existing = getPersistentStringProperty( prop );
 
1127
                        
 
1128
                        if ( existing != null ){
 
1129
                                
 
1130
                                try{
 
1131
                                        persistent_properties.remove( prop );
 
1132
                                        
 
1133
                                        dirty = true;
 
1134
                                        
 
1135
                                }catch( Throwable e ){
 
1136
                                        
 
1137
                                        Debug.printStackTrace(e);
 
1138
                                }
 
1139
                        }
 
1140
                }
 
1141
                
 
1142
                if ( dirty ){
 
1143
                        
 
1144
                        setDirty();
 
1145
                }
 
1146
        }
 
1147
        public String
 
1148
        getError()
 
1149
        {
 
1150
                synchronized( errors ){
 
1151
 
 
1152
                        if ( errors.size() == 0 ){
 
1153
                                
 
1154
                                return( null );
 
1155
                        }
 
1156
                        
 
1157
                        String  res = "";
 
1158
                        
 
1159
                        for ( String s: errors.values()){
 
1160
                                
 
1161
                                res += (res.length()==0?"":"; ") + s;
 
1162
                        }
 
1163
                        
 
1164
                        return( res );
 
1165
                }
 
1166
        }
 
1167
        
 
1168
        protected void
 
1169
        setError(
 
1170
                Object  key,
 
1171
                String  error )
 
1172
        {
 
1173
                boolean changed = false;
 
1174
                
 
1175
                if ( error == null || error.length() == 0 ){
 
1176
                        
 
1177
                        synchronized( errors ){
 
1178
                        
 
1179
                                changed = errors.remove( key ) != null;
 
1180
                        }
 
1181
                }else{
 
1182
                        
 
1183
                        String  existing;
 
1184
                        
 
1185
                        synchronized( errors ){
 
1186
                                
 
1187
                                existing = errors.put( key, error );
 
1188
                        }
 
1189
                        
 
1190
                        changed = existing == null || !existing.equals( error );
 
1191
                }
 
1192
                
 
1193
                if ( changed ){
 
1194
                        
 
1195
                        manager.deviceChanged( this, false );
 
1196
                }
 
1197
        }
 
1198
        
 
1199
        public String
 
1200
        getInfo()
 
1201
        {
 
1202
                synchronized( infos ){
 
1203
 
 
1204
                        if ( infos.size() == 0 ){
 
1205
                                
 
1206
                                return( null );
 
1207
                        }
 
1208
                        
 
1209
                        String  res = "";
 
1210
                        
 
1211
                        for ( String s: infos.values()){
 
1212
                                
 
1213
                                res += (res.length()==0?"":"; ") + s;
 
1214
                        }
 
1215
                        
 
1216
                        return( res );
 
1217
                }
 
1218
        }
 
1219
        
 
1220
        protected void
 
1221
        setInfo(
 
1222
                Object  key,
 
1223
                String  info )
 
1224
        {
 
1225
                boolean changed = false;
 
1226
                
 
1227
                if ( info == null || info.length() == 0 ){
 
1228
                        
 
1229
                        synchronized( infos ){
 
1230
                        
 
1231
                                changed = infos.remove( key ) != null;
 
1232
                        }
 
1233
                }else{
 
1234
                        
 
1235
                        String  existing;
 
1236
                        
 
1237
                        synchronized( infos ){
 
1238
                                
 
1239
                                existing = infos.put( key, info );
 
1240
                        }
 
1241
                        
 
1242
                        changed = existing == null || !existing.equals( info );
 
1243
                }
 
1244
                
 
1245
                if ( changed ){
 
1246
                        
 
1247
                        manager.deviceChanged( this, false );
 
1248
                }
 
1249
        }
 
1250
        
 
1251
        public boolean
 
1252
        getPersistentBooleanProperty(
 
1253
                String          prop,
 
1254
                boolean         def )
 
1255
        {
 
1256
                return( getPersistentStringProperty( prop, def?"true":"false" ).equals( "true" ));
 
1257
        }
 
1258
        
 
1259
        public void
 
1260
        setPersistentBooleanProperty(
 
1261
                String          prop,
 
1262
                boolean         value )
 
1263
        {
 
1264
                setPersistentStringProperty(prop, value?"true":"false" );
 
1265
        }
 
1266
        
 
1267
        public int
 
1268
        getPersistentIntProperty(
 
1269
                String          prop,
 
1270
                int                     def )
 
1271
        {
 
1272
                return( Integer.parseInt( getPersistentStringProperty( prop, String.valueOf(def) )));
 
1273
        }
 
1274
        
 
1275
        public void
 
1276
        setPersistentIntProperty(
 
1277
                String          prop,
 
1278
                int                     value )
 
1279
        {
 
1280
                setPersistentStringProperty(prop, String.valueOf( value ));
 
1281
        }
 
1282
        
 
1283
        public String[]
 
1284
        getPersistentStringListProperty(
 
1285
                String          prop )
 
1286
        {
 
1287
                synchronized( persistent_properties ){
 
1288
                        
 
1289
                        try{
 
1290
                                List<byte[]>    values = (List<byte[]>)persistent_properties.get( prop );
 
1291
                
 
1292
                                if ( values == null ){
 
1293
                                        
 
1294
                                        return( new String[0] );
 
1295
                                }
 
1296
                                
 
1297
                                String[]        res = new String[values.size()];
 
1298
                                
 
1299
                                int     pos = 0;
 
1300
                                
 
1301
                                for (byte[] value: values ){
 
1302
                                
 
1303
                                        res[pos++] = new String( value, "UTF-8" );
 
1304
                                }
 
1305
                                
 
1306
                                return( res );
 
1307
                                
 
1308
                        }catch( Throwable e ){
 
1309
                                
 
1310
                                Debug.printStackTrace(e);
 
1311
                                
 
1312
                                return( new String[0] );
 
1313
                        }
 
1314
                }
 
1315
        }
 
1316
        
 
1317
        public void
 
1318
        setPersistentStringListProperty(
 
1319
                String                  prop,
 
1320
                String[]                values )
 
1321
        {
 
1322
                boolean dirty = false;
 
1323
 
 
1324
                synchronized( persistent_properties ){
 
1325
                        
 
1326
                        try{
 
1327
                                List<byte[]> values_list = new ArrayList<byte[]>();
 
1328
                                
 
1329
                                for (String value: values ){
 
1330
                                        
 
1331
                                        values_list.add( value.getBytes( "UTF-8" ));
 
1332
                                }
 
1333
                                
 
1334
                                persistent_properties.put( prop, values_list );
 
1335
                                
 
1336
                                dirty = true;
 
1337
                                
 
1338
                        }catch( Throwable e ){
 
1339
                                
 
1340
                                Debug.printStackTrace(e);
 
1341
                        }
 
1342
                }
 
1343
                
 
1344
                if ( dirty ){
 
1345
                        
 
1346
                        setDirty();
 
1347
                }
 
1348
        }
 
1349
        
 
1350
        public void
 
1351
        setTransientProperty(
 
1352
                Object          key,
 
1353
                Object          value )
 
1354
        {
 
1355
                synchronized( transient_properties ){
 
1356
                        
 
1357
                        if ( value == null ){
 
1358
                                
 
1359
                                transient_properties.remove( key );
 
1360
                                
 
1361
                        }else{
 
1362
                        
 
1363
                                transient_properties.put( key, value );
 
1364
                        }
 
1365
                }
 
1366
        }
 
1367
        
 
1368
        public Object
 
1369
        getTransientProperty(
 
1370
                Object          key )
 
1371
        {
 
1372
                synchronized( transient_properties ){
 
1373
                        
 
1374
                        return( transient_properties.get( key ));
 
1375
                }
 
1376
        }
 
1377
        
 
1378
        public void
 
1379
        setTransientProperty(
 
1380
                Object          key1,
 
1381
                Object          key2,
 
1382
                Object          value )
 
1383
        {
 
1384
                synchronized( transient_properties ){
 
1385
                        
 
1386
                        Map<Object,Object> l1 = (Map<Object,Object>)transient_properties.get( key1 );
 
1387
                        
 
1388
                        if ( l1 == null ){
 
1389
                                
 
1390
                                if ( value == null ){
 
1391
                                        
 
1392
                                        return;
 
1393
                                }
 
1394
                                
 
1395
                                l1 = new HashMap<Object, Object>();
 
1396
                                
 
1397
                                transient_properties.put( key1, l1 );
 
1398
                        }
 
1399
                        
 
1400
                        if ( value == null ){
 
1401
                                
 
1402
                                l1.remove( key2 );
 
1403
                                
 
1404
                                if ( l1.size() == 0 ){
 
1405
                                        
 
1406
                                        transient_properties.remove( key1 );    
 
1407
                                }
 
1408
                        }else{
 
1409
                                
 
1410
                                l1.put( key2, value );
 
1411
                        }
 
1412
                }
 
1413
        }
 
1414
        
 
1415
        public Object
 
1416
        getTransientProperty(
 
1417
                Object          key1,
 
1418
                Object          key2 )
 
1419
        {
 
1420
                synchronized( transient_properties ){
 
1421
                        
 
1422
                        Map<Object,Object> l1 = (Map<Object,Object>)transient_properties.get( key1 );
 
1423
                        
 
1424
                        if ( l1 == null ){
 
1425
                                
 
1426
                                return( null );
 
1427
                        }
 
1428
 
 
1429
                        return( l1.get( key2 ));
 
1430
                }
 
1431
        }
 
1432
        
 
1433
        protected void
 
1434
        close()
 
1435
        {
 
1436
                synchronized( this ){
 
1437
 
 
1438
                        if ( device_files_dirty ){
 
1439
                                
 
1440
                                saveDeviceFile();
 
1441
                        }
 
1442
                }
 
1443
        }
 
1444
        
 
1445
        protected void
 
1446
        loadDeviceFile()
 
1447
        
 
1448
                throws IOException
 
1449
        {
 
1450
                device_files_last_mod = SystemTime.getMonotonousTime();
 
1451
                
 
1452
                if ( device_files_ref != null ){
 
1453
                
 
1454
                        device_files = device_files_ref.get();
 
1455
                }
 
1456
                
 
1457
                if ( device_files == null ){
 
1458
                        
 
1459
                        Map     map = FileUtil.readResilientFile( getDeviceFile());
 
1460
        
 
1461
                        device_files = (Map<String,Map<String,?>>)map.get( "files" );
 
1462
                        
 
1463
                        if ( device_files == null ){
 
1464
                                
 
1465
                                device_files = new HashMap<String, Map<String,?>>();
 
1466
                        }
 
1467
                
 
1468
                        device_files_ref = new WeakReference<Map<String,Map<String,?>>>( device_files );
 
1469
                        
 
1470
                        log( "Loaded device file for " + getName() + ": files=" + device_files.size());
 
1471
                }
 
1472
                
 
1473
                final int GC_TIME = 15000;
 
1474
                
 
1475
                new DelayedEvent( 
 
1476
                        "Device:gc", 
 
1477
                        GC_TIME,
 
1478
                        new AERunnable()
 
1479
                        {
 
1480
                                public void
 
1481
                                runSupport()
 
1482
                                {
 
1483
                                        synchronized( DeviceImpl.this ){
 
1484
                                                
 
1485
                                                if ( SystemTime.getMonotonousTime() - device_files_last_mod >= GC_TIME ){
 
1486
                                                                
 
1487
                                                        if ( device_files_dirty ){
 
1488
                                                                
 
1489
                                                                saveDeviceFile();
 
1490
                                                        }
 
1491
                                                        
 
1492
                                                        device_files = null;
 
1493
                                                        
 
1494
                                                }else{
 
1495
                                                        
 
1496
                                                        new DelayedEvent( "Device:gc2", GC_TIME, this );
 
1497
                                                }
 
1498
                                        }
 
1499
                                }
 
1500
                        });
 
1501
        }
 
1502
        
 
1503
        protected URL
 
1504
        getStreamURL(
 
1505
                TranscodeFileImpl               file )
 
1506
        {
 
1507
                return( manager.getStreamURL( file ));
 
1508
        }
 
1509
        
 
1510
        protected void
 
1511
        deleteFile(
 
1512
                TranscodeFileImpl       file,
 
1513
                boolean                         delete_contents,
 
1514
                boolean                         remove )
 
1515
        
 
1516
                throws TranscodeException 
 
1517
        {       
 
1518
                if ( file.isDeleted()){
 
1519
                        
 
1520
                        return;
 
1521
                }
 
1522
                
 
1523
                if ( delete_contents ){
 
1524
                        
 
1525
                        File f = file.getCacheFile();
 
1526
                                
 
1527
                        int      time = 0;
 
1528
                        
 
1529
                        while( f.exists() && !f.delete()){
 
1530
                                                
 
1531
                                if ( time > 3000 ){
 
1532
                                
 
1533
                                        log( "Failed to remove file '" + f.getAbsolutePath() + "'" );
 
1534
                                        
 
1535
                                        break;
 
1536
                                        
 
1537
                                }else{
 
1538
                                        
 
1539
                                        try{
 
1540
                                                Thread.sleep(500);
 
1541
                                                
 
1542
                                        }catch( Throwable e ){
 
1543
                                                
 
1544
                                        }
 
1545
                                        
 
1546
                                        time += 500;
 
1547
                                }
 
1548
                        }
 
1549
                }
 
1550
                
 
1551
                if ( remove ){
 
1552
                        
 
1553
                        try{
 
1554
                                synchronized( this ){
 
1555
                                        
 
1556
                                        if ( device_files == null ){
 
1557
                                                
 
1558
                                                loadDeviceFile();
 
1559
                                                
 
1560
                                        }else{
 
1561
                                                
 
1562
                                                device_files_last_mod = SystemTime.getMonotonousTime();
 
1563
                                        }
 
1564
                                        
 
1565
                                        device_files.remove( file.getKey());
 
1566
                                        
 
1567
                                        device_files_dirty      = true;
 
1568
                                }
 
1569
                                
 
1570
                                for ( TranscodeTargetListener l: listeners ){
 
1571
                                        
 
1572
                                        try{
 
1573
                                                l.fileRemoved( file );
 
1574
                                                
 
1575
                                        }catch( Throwable e ){
 
1576
                                                
 
1577
                                                Debug.out( e );
 
1578
                                        }
 
1579
                                }
 
1580
                        }catch( Throwable e ){
 
1581
                                
 
1582
                                throw( new TranscodeException( "Delete failed", e ));
 
1583
                        }
 
1584
                }
 
1585
        }
 
1586
        
 
1587
        protected void
 
1588
        fileDirty(
 
1589
                TranscodeFileImpl       file,
 
1590
                int                                     type,
 
1591
                Object                          data )
 
1592
        {
 
1593
                try{
 
1594
                        synchronized( this ){
 
1595
                                
 
1596
                                if ( device_files == null ){
 
1597
                                        
 
1598
                                        loadDeviceFile();
 
1599
                                        
 
1600
                                }else{
 
1601
                                        
 
1602
                                        device_files_last_mod = SystemTime.getMonotonousTime();
 
1603
                                }
 
1604
                        }
 
1605
                        
 
1606
                        device_files_dirty      = true;
 
1607
                        
 
1608
                }catch( Throwable e ){
 
1609
                        
 
1610
                        Debug.out( "Failed to load device file", e );
 
1611
                }
 
1612
                
 
1613
                for ( TranscodeTargetListener l: listeners ){
 
1614
                        
 
1615
                        try{
 
1616
                                l.fileChanged( file, type, data );
 
1617
                                
 
1618
                        }catch( Throwable e ){
 
1619
                                
 
1620
                                Debug.out( e );
 
1621
                        }
 
1622
                }
 
1623
        }
 
1624
        
 
1625
        protected void
 
1626
        saveDeviceFile()
 
1627
        {
 
1628
                device_files_dirty = false;
 
1629
                
 
1630
                try{
 
1631
                        loadDeviceFile();
 
1632
                        
 
1633
                        if ( device_files == null || device_files.size()==0 ){
 
1634
                                
 
1635
                                FileUtil.deleteResilientFile( getDeviceFile());
 
1636
                                
 
1637
                        }else{
 
1638
                                Map map = new HashMap();
 
1639
                                
 
1640
                                map.put( "files", device_files );
 
1641
                                
 
1642
                                FileUtil.writeResilientFile( getDeviceFile(), map );
 
1643
                        }
 
1644
                }catch( Throwable e ){
 
1645
                        
 
1646
                        Debug.out( "Failed to save device file", e );
 
1647
                }
 
1648
        }
 
1649
        
 
1650
        protected File
 
1651
        getDeviceFile()
 
1652
        
 
1653
                throws IOException
 
1654
        {
 
1655
                File dir = getDevicesDir();
 
1656
                
 
1657
                return( new File( dir, FileUtil.convertOSSpecificChars(getID(),false) + ".dat" ));
 
1658
        }
 
1659
        
 
1660
        protected File
 
1661
        getDevicesDir()
 
1662
        
 
1663
                throws IOException
 
1664
        {
 
1665
                File dir = new File(SystemProperties.getUserPath());
 
1666
 
 
1667
                dir = new File( dir, "devices" );
 
1668
                
 
1669
                if ( !dir.exists()){
 
1670
                        
 
1671
                        if ( !dir.mkdirs()){
 
1672
                                
 
1673
                                throw( new IOException( "Failed to create '" + dir + "'" ));
 
1674
                        }
 
1675
                }       
 
1676
                
 
1677
                return( dir );
 
1678
        }
 
1679
        
 
1680
        protected DeviceManagerImpl
 
1681
        getManager()
 
1682
        {
 
1683
                return( manager );
 
1684
        }
 
1685
 
 
1686
        public void
 
1687
        addListener(
 
1688
                TranscodeTargetListener         listener )
 
1689
        {
 
1690
                if (!listeners.contains(listener)) {
 
1691
                        listeners.add( listener );
 
1692
                }
 
1693
        }
 
1694
        
 
1695
        public void
 
1696
        removeListener(
 
1697
                TranscodeTargetListener         listener )
 
1698
        {
 
1699
                listeners.remove( listener );
 
1700
        }
 
1701
        
 
1702
        protected void
 
1703
        log(
 
1704
                String          str )
 
1705
        {
 
1706
                manager.log( str );
 
1707
        }
 
1708
        
 
1709
        protected void
 
1710
        log(
 
1711
                String          str,
 
1712
                Throwable       e )
 
1713
        {
 
1714
                manager.log( str, e );
 
1715
        }
 
1716
        
 
1717
        public String
 
1718
        getString()
 
1719
        {
 
1720
                return( "type=" + type + ",uid=" + uid + ",name=" + name );
 
1721
        }
 
1722
        
 
1723
        public void
 
1724
        generate(
 
1725
                IndentWriter            writer )
 
1726
        {
 
1727
                writer.println( getName() + "/" + getID() + "/" + type );
 
1728
                
 
1729
                try{
 
1730
                        writer.indent();
 
1731
                        
 
1732
                        writer.println( 
 
1733
                                "hidden=" + hidden + 
 
1734
                                ", last_seen=" + new SimpleDateFormat().format(new Date(last_seen)) +
 
1735
                                ", online=" + online +
 
1736
                                ", transcoding=" + transcoding );
 
1737
                        
 
1738
                        writer.println( "p_props=" + persistent_properties );
 
1739
                        writer.println( "t_props=" + transient_properties );
 
1740
                        
 
1741
                        writer.println( "errors=" + errors );
 
1742
                        writer.println( "infos=" + infos );
 
1743
                }finally{
 
1744
                        
 
1745
                        writer.exdent();
 
1746
                }
 
1747
        }
 
1748
        
 
1749
        public void
 
1750
        generateTT(
 
1751
                IndentWriter            writer )
 
1752
        {
 
1753
                TranscodeFileImpl[] files = getFiles();
 
1754
                
 
1755
                int     complete         = 0;
 
1756
                int     copied           = 0;
 
1757
                int     deleted         = 0;
 
1758
                int     template         = 0;
 
1759
                
 
1760
                for ( TranscodeFileImpl f: files ){
 
1761
                        
 
1762
                        if ( f.isComplete()){
 
1763
                                
 
1764
                                complete++;
 
1765
                        }
 
1766
                        
 
1767
                        if ( f.isCopiedToDevice()){
 
1768
                                
 
1769
                                copied++;
 
1770
                        }
 
1771
                        
 
1772
                        if ( f.isDeleted()){
 
1773
                                
 
1774
                                deleted++;
 
1775
                        }
 
1776
                        
 
1777
                        if ( f.isTemplate()){
 
1778
                                
 
1779
                                template++;
 
1780
                        }
 
1781
                }
 
1782
                
 
1783
                writer.println( "files=" + files.length + ", comp=" + complete + ", copied=" + copied + ", deleted=" + deleted + ", template=" + template );
 
1784
        }
 
1785
        
 
1786
        protected class
 
1787
        browseLocationImpl
 
1788
                implements browseLocation
 
1789
        {
 
1790
                private String          name;
 
1791
                private URL                     url;
 
1792
                
 
1793
                protected
 
1794
                browseLocationImpl(
 
1795
                        String          _name,
 
1796
                        URL                     _url )
 
1797
                {
 
1798
                        name            = _name;
 
1799
                        url                     = _url;
 
1800
                }
 
1801
                
 
1802
                public String
 
1803
                getName()
 
1804
                {
 
1805
                        return( name );
 
1806
                }
 
1807
                
 
1808
                public URL
 
1809
                getURL()
 
1810
                {
 
1811
                        return( url );
 
1812
                }
 
1813
        }
 
1814
}