/[svn]/jlscp/trunk/src/org/linuxsampler/lscp/Client.java
ViewVC logotype

Diff of /jlscp/trunk/src/org/linuxsampler/lscp/Client.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1139 by iliev, Mon Apr 2 20:43:58 2007 UTC revision 1766 by iliev, Mon Sep 8 00:16:17 2008 UTC
# Line 1  Line 1 
1  /*  /*
2   *   jlscp - a java LinuxSampler control protocol API   *   jlscp - a java LinuxSampler control protocol API
3   *   *
4   *   Copyright (C) 2005-2007 Grigor Iliev <grigor@grigoriliev.com>   *   Copyright (C) 2005-2008 Grigor Iliev <grigor@grigoriliev.com>
5   *   *
6   *   This file is part of jlscp.   *   This file is part of jlscp.
7   *   *
# Line 34  import java.util.Vector; Line 34  import java.util.Vector;
34  import java.util.logging.Level;  import java.util.logging.Level;
35  import java.util.logging.Logger;  import java.util.logging.Logger;
36    
 import static org.linuxsampler.lscp.Parser.*;  
37  import org.linuxsampler.lscp.event.*;  import org.linuxsampler.lscp.event.*;
38    
39    import static org.linuxsampler.lscp.Parser.*;
40    
41    
42  /**  /**
43   * This class is the abstraction representing a client endpoint for communication with LinuxSampler   * This class is the abstraction representing a client endpoint for communication with LinuxSampler
44   * instance. Since it implements all commands specified in the LSCP protocol v1.1, for more   * instance. Since it implements all commands specified in the LSCP protocol v1.2, for more
45   * information look at the   * information look at the
46   * <a href=http://www.linuxsampler.org/api/lscp-1.1.html>LSCP</a> specification.   * <a href=http://www.linuxsampler.org/api/lscp-1.2.html>LSCP</a> specification.
47   *   *
48   * <p> The following code establishes connection to LinuxSampler instance and gets the   * <p> The following code establishes connection to LinuxSampler instance and gets the
49   * LinuxSampler version:   * LinuxSampler version:
# Line 69  public class Client { Line 70  public class Client {
70          private String address;          private String address;
71          private int port;          private int port;
72          private Socket sock = null;          private Socket sock = null;
73          private int soTimeout = 10000;          private int soTimeout = 20000;
74                    
75          private LscpInputStream in = null;          private LscpInputStream in = null;
76          private LscpOutputStream out = null;          private LscpOutputStream out = null;
# Line 79  public class Client { Line 80  public class Client {
80          private boolean printOnlyMode = false;          private boolean printOnlyMode = false;
81                    
82          class EventThread extends Thread {          class EventThread extends Thread {
83                    private Vector<String> queue = new Vector<String>();
84                  private boolean terminate = false;                  private boolean terminate = false;
85                                    
86                  EventThread() { super("LSCP-Event-Thread"); }                  EventThread() { super("LSCP-Event-Thread"); }
# Line 86  public class Client { Line 88  public class Client {
88                  public void                  public void
89                  run() {                  run() {
90                          while(!mustTerminate()) {                          while(!mustTerminate()) {
91                                  try { processNotifications(); }                                  try {
92                                  catch(Exception x) {                                          processQueue();
93                                            processNotifications();
94                                    } catch(Exception x) {
95                                          getLogger().log(Level.FINE, x.getMessage(), x);                                          getLogger().log(Level.FINE, x.getMessage(), x);
96                                  }                                  }
97                                  try { synchronized(this) { wait(100); } }                                  try { synchronized(this) { wait(100); } }
# Line 105  public class Client { Line 109  public class Client {
109                          terminate = true;                          terminate = true;
110                          this.notifyAll();                          this.notifyAll();
111                  }                  }
112                    
113                    public synchronized void
114                    scheduleNotification(String s) { queue.add(s); }
115                    
116                    private void
117                    processQueue() {
118                            String[] notifications = popAllNotifications();
119                            for(String n : notifications) fireEvent(n);
120                    }
121                    
122                    private synchronized String[]
123                    popAllNotifications() {
124                            String[] notifications = queue.toArray(new String[queue.size()]);
125                            queue.removeAllElements();
126                            return notifications;
127                    }
128          }          }
129                    
130          /**          /**
# Line 144  public class Client { Line 164  public class Client {
164                  if(printOnlyMode) setPrintOnlyMode(true);                  if(printOnlyMode) setPrintOnlyMode(true);
165          }          }
166                    
167            private boolean extendedCharacterEscaping = true;
168            
169            /**
170             * Sets whether strings sent to LinuxSampler should be more aggressively escaped.
171             */
172            public synchronized void
173            setExtendedCharacterEscaping(boolean b) { extendedCharacterEscaping = b; }
174            
175            /**
176             * Determines whether strings sent to LinuxSampler should be more aggressively escaped.
177             */
178            public synchronized boolean
179            getExtendedCharacterEscaping() { return extendedCharacterEscaping; }
180            
181            /**
182             * @see java.net.Socket#setSoTimeout
183             */
184            public synchronized void
185            setSoTimeout(int timeout) {
186                    soTimeout = timeout;
187                    
188                    try { if(sock != null) sock.setSoTimeout(timeout); }
189                    catch(Exception x) { this.getLogger().log(Level.INFO, "Unable to set timeout", x); }
190            }
191            
192            private String
193            toEscapedText(String s) {
194                    s = toEscapedString(s);
195                    return conv(s);
196            }
197            
198            private String
199            toEscapedFsEntry(String s) {
200                    s = toEscapedFileName(s);
201                    return conv(s);
202            }
203            
204            /**
205             * Applies an extended character escaping to the specified string if needed.
206             */
207            private String
208            conv(String s) {
209                    return getExtendedCharacterEscaping() ? toExtendedEscapeSequence(s) : s;
210            }
211            
212          /**          /**
213           * Determines whether the client is in print-only mode.           * Determines whether the client is in print-only mode.
214           * Print-only mode means that the client will just print all           * Print-only mode means that the client will just print all
# Line 324  public class Client { Line 389  public class Client {
389                  if(!llFSI.isEmpty()) subscribe("FX_SEND_INFO");                  if(!llFSI.isEmpty()) subscribe("FX_SEND_INFO");
390                  if(!llSC.isEmpty()) subscribe("STREAM_COUNT");                  if(!llSC.isEmpty()) subscribe("STREAM_COUNT");
391                  if(!llVC.isEmpty()) subscribe("VOICE_COUNT");                  if(!llVC.isEmpty()) subscribe("VOICE_COUNT");
392                    if(!llTSC.isEmpty()) subscribe("TOTAL_STREAM_COUNT");
393                  if(!llTVC.isEmpty()) subscribe("TOTAL_VOICE_COUNT");                  if(!llTVC.isEmpty()) subscribe("TOTAL_VOICE_COUNT");
394                  if(!llMIMC.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_COUNT");                  if(!llMIMC.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_COUNT");
395                  if(!llMIMI.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_INFO");                  if(!llMIMI.isEmpty()) subscribe("MIDI_INSTRUMENT_MAP_INFO");
396                  if(!llMIC.isEmpty()) subscribe("MIDI_INSTRUMENT_COUNT");                  if(!llMIC.isEmpty()) subscribe("MIDI_INSTRUMENT_COUNT");
397                  if(!llMII.isEmpty()) subscribe("MIDI_INSTRUMENT_INFO");                  if(!llMII.isEmpty()) subscribe("MIDI_INSTRUMENT_INFO");
398                    if(!llDMD.isEmpty()) subscribe("DEVICE_MIDI");
399                    if(!llCMD.isEmpty()) subscribe("CHANNEL_MIDI");
400                    if(!llID.isEmpty()) {
401                            subscribe("DB_INSTRUMENT_DIRECTORY_COUNT");
402                            subscribe("DB_INSTRUMENT_DIRECTORY_INFO");
403                            subscribe("DB_INSTRUMENT_COUNT");
404                            subscribe("DB_INSTRUMENT_INFO");
405                            subscribe("DB_INSTRUMENTS_JOB_INFO");
406                    }
407                  if(!llGI.isEmpty()) subscribe("GLOBAL_INFO");                  if(!llGI.isEmpty()) subscribe("GLOBAL_INFO");
408          }          }
409                    
# Line 376  public class Client { Line 451  public class Client {
451                  String s;                  String s;
452                  for(;;) {                  for(;;) {
453                          s = in.readLine();                          s = in.readLine();
454                          if(s.startsWith("NOTIFY:")) fireEvent(s.substring("NOTIFY:".length()));                          if(s.startsWith("NOTIFY:")) {
455                                    eventThread.scheduleNotification(s.substring("NOTIFY:".length()));
456                            }
457                          else break;                          else break;
458                  }                  }
459                  return s;                  return s;
# Line 457  public class Client { Line 534  public class Client {
534          private final Vector<ItemInfoListener> llMIDI = new Vector<ItemInfoListener>();          private final Vector<ItemInfoListener> llMIDI = new Vector<ItemInfoListener>();
535          private final Vector<StreamCountListener> llSC = new Vector<StreamCountListener>();          private final Vector<StreamCountListener> llSC = new Vector<StreamCountListener>();
536          private final Vector<VoiceCountListener> llVC = new Vector<VoiceCountListener>();          private final Vector<VoiceCountListener> llVC = new Vector<VoiceCountListener>();
537            private final Vector<TotalStreamCountListener> llTSC = new Vector<TotalStreamCountListener>();
538          private final Vector<TotalVoiceCountListener> llTVC = new Vector<TotalVoiceCountListener>();          private final Vector<TotalVoiceCountListener> llTVC = new Vector<TotalVoiceCountListener>();
539                    
540          /** MIDI instrument map count listeners */          /** MIDI instrument map count listeners */
# Line 469  public class Client { Line 547  public class Client {
547          /** MIDI instrument info listeners */          /** MIDI instrument info listeners */
548          private final Vector<MidiInstrumentInfoListener> llMII =          private final Vector<MidiInstrumentInfoListener> llMII =
549                  new Vector<MidiInstrumentInfoListener>();                  new Vector<MidiInstrumentInfoListener>();
550            private final Vector<DeviceMidiDataListener> llDMD = new Vector<DeviceMidiDataListener>();
551            private final Vector<ChannelMidiDataListener> llCMD = new Vector<ChannelMidiDataListener>();
552            private final Vector<InstrumentsDbListener> llID = new Vector<InstrumentsDbListener>();
553          private final Vector<GlobalInfoListener> llGI = new Vector<GlobalInfoListener>();          private final Vector<GlobalInfoListener> llGI = new Vector<GlobalInfoListener>();
554                    
555                    
# Line 493  public class Client { Line 574  public class Client {
574                          !llMIDI.isEmpty() ||                          !llMIDI.isEmpty() ||
575                          !llSC.isEmpty()   ||                          !llSC.isEmpty()   ||
576                          !llVC.isEmpty()   ||                          !llVC.isEmpty()   ||
577                            !llTSC.isEmpty()  ||
578                          !llTVC.isEmpty()  ||                          !llTVC.isEmpty()  ||
579                          !llMIMC.isEmpty() ||                          !llMIMC.isEmpty() ||
580                          !llMIMI.isEmpty() ||                          !llMIMI.isEmpty() ||
581                          !llMIC.isEmpty()  ||                          !llMIC.isEmpty()  ||
582                          !llMII.isEmpty()  ||                          !llMII.isEmpty()  ||
583                            !llDMD.isEmpty()  ||
584                            !llCMD.isEmpty()  ||
585                            !llID.isEmpty()   ||
586                          !llGI.isEmpty();                          !llGI.isEmpty();
587          }          }
588                    
589          private void          private synchronized void
590            fireDeviceMidiDataEvent(String s) {
591                    try {
592                            String[] list = parseStringList(s, ' ');
593                            if(list.length != 5) {
594                                    getLogger().warning("Unknown DEVICE_MIDI format");
595                                    return;
596                            }
597                            
598                            int dev = parseInt(list[0]);
599                            int port = parseInt(list[1]);
600                            
601                            MidiDataEvent.Type type = parseMidiDataType(list[2]);
602                            if(type == null) return;
603                            
604                            int note = parseInt(list[3]);
605                            int velocity = parseInt(list[4]);
606                            
607                            DeviceMidiDataEvent e = new DeviceMidiDataEvent(this, type, note, velocity);
608                            e.setDeviceId(dev);
609                            e.setPortId(port);
610                            for(DeviceMidiDataListener l : llDMD) l.midiDataArrived(e);
611                    } catch(LscpException x) {
612                            getLogger().log (
613                                    Level.WARNING, LscpI18n.getLogMsg("CommandFailed!"), x
614                            );
615                    }
616            }
617            
618            private synchronized void
619            fireChannelMidiDataEvent(String s) {
620                    try {
621                            String[] list = parseStringList(s, ' ');
622                            if(list.length != 4) {
623                                    getLogger().warning("Unknown CHANNEL_MIDI format");
624                                    return;
625                            }
626                            
627                            int channel = parseInt(list[0]);
628                            
629                            MidiDataEvent.Type type = parseMidiDataType(list[1]);
630                            if(type == null) return;
631                            
632                            int note = parseInt(list[2]);
633                            int velocity = parseInt(list[3]);
634                            
635                            ChannelMidiDataEvent e = new ChannelMidiDataEvent(this, type, note, velocity);
636                            e.setChannelId(channel);
637                            for(ChannelMidiDataListener l : llCMD) l.midiDataArrived(e);
638                    } catch(LscpException x) {
639                            getLogger().log (
640                                    Level.WARNING, LscpI18n.getLogMsg("CommandFailed!"), x
641                            );
642                    }
643            }
644            
645            private MidiDataEvent.Type
646            parseMidiDataType(String s) {
647                    if("NOTE_ON".equals(s)) return MidiDataEvent.Type.NOTE_ON;
648                    if("NOTE_OFF".equals(s)) return MidiDataEvent.Type.NOTE_OFF;
649                    
650                    getLogger().warning("Unknown MIDI data type: " + s);
651                    return null;
652            }
653            
654            private synchronized void
655          fireEvent(String s) {          fireEvent(String s) {
656                  if(s.startsWith("CHANNEL_COUNT:")) {                  // Sort by priority
657                    
658                     if(s.startsWith("CHANNEL_MIDI:")) {
659                            s = s.substring("CHANNEL_MIDI:".length());
660                            fireChannelMidiDataEvent(s);
661                    } else if(s.startsWith("DEVICE_MIDI:")) {
662                            s = s.substring("DEVICE_MIDI:".length());
663                            fireDeviceMidiDataEvent(s);
664                    } else if(s.startsWith("DB_INSTRUMENT_DIRECTORY_COUNT:")) {
665                            s = s.substring("DB_INSTRUMENT_DIRECTORY_COUNT:".length());
666                            InstrumentsDbEvent e = new InstrumentsDbEvent(this, s);
667                            for(InstrumentsDbListener l : llID) l.directoryCountChanged(e);
668                    } else if(s.startsWith("DB_INSTRUMENT_DIRECTORY_INFO:")) {
669                            InstrumentsDbEvent e;
670                            s = s.substring("DB_INSTRUMENT_DIRECTORY_INFO:".length());
671                            if(s.startsWith("NAME ")) {
672                                    String[] list;
673                                    try {
674                                            s = s.substring("NAME ".length());
675                                            list = parseEscapedStringList(s, ' ');
676                                            if(list.length != 2) throw new LscpException();
677                                            list[1] = toNonEscapedString(list[1]);
678                                            e = new InstrumentsDbEvent(this, list[0], list[1]);
679                                            for(InstrumentsDbListener l : llID) {
680                                                    l.directoryNameChanged(e);
681                                            }
682                                    } catch(LscpException x) {
683                                            getLogger().log (
684                                                    Level.WARNING,
685                                                    LscpI18n.getLogMsg("CommandFailed!"),
686                                                    x
687                                            );
688                                    }
689                            } else {
690                                    e = new InstrumentsDbEvent(this, s);
691                                    for(InstrumentsDbListener l : llID) l.directoryInfoChanged(e);
692                            }
693                    } else if(s.startsWith("DB_INSTRUMENT_COUNT:")) {
694                            s = s.substring("DB_INSTRUMENT_COUNT:".length());
695                            InstrumentsDbEvent e = new InstrumentsDbEvent(this, s);
696                            for(InstrumentsDbListener l : llID) l.instrumentCountChanged(e);
697                    } else if(s.startsWith("DB_INSTRUMENT_INFO:")) {
698                            InstrumentsDbEvent e;
699                            s = s.substring("DB_INSTRUMENT_INFO:".length());
700                            if(s.startsWith("NAME ")) {
701                                    String[] list;
702                                    try {
703                                            s = s.substring("NAME ".length());
704                                            list = parseEscapedStringList(s, ' ');
705                                            if(list.length != 2) throw new LscpException();
706                                            list[1] = toNonEscapedString(list[1]);
707                                            e = new InstrumentsDbEvent(this, list[0], list[1]);
708                                            for(InstrumentsDbListener l : llID) {
709                                                    l.instrumentNameChanged(e);
710                                            }
711                                    } catch(LscpException x) {
712                                            getLogger().log (
713                                                    Level.WARNING,
714                                                    LscpI18n.getLogMsg("CommandFailed!"),
715                                                    x
716                                            );
717                                    }
718                            } else {
719                                    e = new InstrumentsDbEvent(this, s);
720                                    for(InstrumentsDbListener l : llID) l.instrumentInfoChanged(e);
721                            }
722                    } else if(s.startsWith("DB_INSTRUMENTS_JOB_INFO:")) {
723                            s = s.substring("DB_INSTRUMENTS_JOB_INFO:".length());
724                            try {
725                                    int i = Integer.parseInt(s);
726                                    InstrumentsDbEvent e = new InstrumentsDbEvent(this, i);
727                                    for(InstrumentsDbListener l : llID) l.jobStatusChanged(e);
728                            } catch(NumberFormatException x) {
729                                    s = "Unknown DB_INSTRUMENTS_JOB_INFO format";
730                                    getLogger().log(Level.WARNING, s, x);
731                            }
732                            
733                    } else if(s.startsWith("CHANNEL_COUNT:")) {
734                          try {                          try {
735                                  int i = Integer.parseInt(s.substring("CHANNEL_COUNT:".length()));                                  int i = Integer.parseInt(s.substring("CHANNEL_COUNT:".length()));
736                                  ChannelCountEvent e = new ChannelCountEvent(this, i);                                  ChannelCountEvent e = new ChannelCountEvent(this, i);
# Line 563  public class Client { Line 790  public class Client {
790                          } catch(NumberFormatException x) {                          } catch(NumberFormatException x) {
791                                  getLogger().log(Level.WARNING, "Unknown CHANNEL_INFO format", x);                                  getLogger().log(Level.WARNING, "Unknown CHANNEL_INFO format", x);
792                          }                          }
793                    } else if(s.startsWith("TOTAL_STREAM_COUNT:")) {
794                            try {
795                                    s = s.substring("TOTAL_STREAM_COUNT:".length());
796                                    int i = Integer.parseInt(s);
797                                    TotalStreamCountEvent e = new TotalStreamCountEvent(this, i);
798                                    for(TotalStreamCountListener l : llTSC) l.totalStreamCountChanged(e);
799                            } catch(NumberFormatException x) {
800                                    getLogger().log (
801                                            Level.WARNING, "Unknown TOTAL_STREAM_COUNT format", x
802                                    );
803                            }
804                  } else if(s.startsWith("TOTAL_VOICE_COUNT:")) {                  } else if(s.startsWith("TOTAL_VOICE_COUNT:")) {
805                          try {                          try {
806                                  s = s.substring("TOTAL_VOICE_COUNT:".length());                                  s = s.substring("TOTAL_VOICE_COUNT:".length());
# Line 1035  public class Client { Line 1273  public class Client {
1273          /**          /**
1274           * Registers the specified listener for receiving event messages.           * Registers the specified listener for receiving event messages.
1275           * Listeners can be registered regardless of the connection state.           * Listeners can be registered regardless of the connection state.
1276             * @param l The <code>TotalStreamCountListener</code> to register.
1277             */
1278            public synchronized void
1279            addTotalStreamCountListener(TotalStreamCountListener l) {
1280                    if(llTSC.isEmpty()) subscribe("TOTAL_STREAM_COUNT");
1281                    llTSC.add(l);
1282            }
1283            
1284            /**
1285             * Removes the specified listener.
1286             * Listeners can be removed regardless of the connection state.
1287             * @param l The <code>TotalStreamCountListener</code> to remove.
1288             */
1289            public synchronized void
1290            removeTotalStreamCountListener(TotalStreamCountListener l) {
1291                    boolean b = llTSC.remove(l);
1292                    if(b && llTSC.isEmpty()) unsubscribe("TOTAL_STREAM_COUNT");
1293            }
1294            
1295            /**
1296             * Registers the specified listener for receiving event messages.
1297             * Listeners can be registered regardless of the connection state.
1298           * @param l The <code>TotalVoiceCountListener</code> to register.           * @param l The <code>TotalVoiceCountListener</code> to register.
1299           */           */
1300          public synchronized void          public synchronized void
# Line 1145  public class Client { Line 1405  public class Client {
1405          /**          /**
1406           * Registers the specified listener for receiving event messages.           * Registers the specified listener for receiving event messages.
1407           * Listeners can be registered regardless of the connection state.           * Listeners can be registered regardless of the connection state.
1408             * @param l The <code>DeviceMidiDataListener</code> to register.
1409             */
1410            public synchronized void
1411            addDeviceMidiDataListener(DeviceMidiDataListener l) {
1412                    if(llDMD.isEmpty()) subscribe("DEVICE_MIDI");
1413                    llDMD.add(l);
1414            }
1415            
1416            /**
1417             * Removes the specified listener.
1418             * Listeners can be removed regardless of the connection state.
1419             * @param l The <code>DeviceMidiDataListener</code> to remove.
1420             */
1421            public synchronized void
1422            removeDeviceMidiDataListener(DeviceMidiDataListener l) {
1423                    boolean b = llDMD.remove(l);
1424                    if(b && llDMD.isEmpty()) unsubscribe("DEVICE_MIDI");
1425            }
1426            
1427            /**
1428             * Registers the specified listener for receiving event messages.
1429             * Listeners can be registered regardless of the connection state.
1430             * @param l The <code>ChannelMidiDataListener</code> to register.
1431             */
1432            public synchronized void
1433            addChannelMidiDataListener(ChannelMidiDataListener l) {
1434                    if(llCMD.isEmpty()) subscribe("CHANNEL_MIDI");
1435                    llCMD.add(l);
1436            }
1437            
1438            /**
1439             * Removes the specified listener.
1440             * Listeners can be removed regardless of the connection state.
1441             * @param l The <code>ChannelMidiDataListener</code> to remove.
1442             */
1443            public synchronized void
1444            removeChannelMidiDataListener(ChannelMidiDataListener l) {
1445                    boolean b = llCMD.remove(l);
1446                    if(b && llCMD.isEmpty()) unsubscribe("CHANNEL_MIDI");
1447            }
1448            
1449            /**
1450             * Registers the specified listener for receiving event messages.
1451             * Listeners can be registered regardless of the connection state.
1452             * @param l The <code>InstrumentsDbListener</code> to register.
1453             */
1454            public synchronized void
1455            addInstrumentsDbListener(InstrumentsDbListener l) {
1456                    if(llID.isEmpty()) {
1457                            subscribe("DB_INSTRUMENT_DIRECTORY_COUNT");
1458                            subscribe("DB_INSTRUMENT_DIRECTORY_INFO");
1459                            subscribe("DB_INSTRUMENT_COUNT");
1460                            subscribe("DB_INSTRUMENT_INFO");
1461                            subscribe("DB_INSTRUMENTS_JOB_INFO");
1462                    }
1463                    llID.add(l);
1464            }
1465            
1466            /**
1467             * Removes the specified listener.
1468             * Listeners can be removed regardless of the connection state.
1469             * @param l The <code>InstrumentsDbListener</code> to remove.
1470             */
1471            public synchronized void
1472            removeInstrumentsDbListener(InstrumentsDbListener l) {
1473                    boolean b = llID.remove(l);
1474                    if(b && llID.isEmpty()) {
1475                            unsubscribe("DB_INSTRUMENT_DIRECTORY_COUNT");
1476                            unsubscribe("DB_INSTRUMENT_DIRECTORY_INFO");
1477                            unsubscribe("DB_INSTRUMENT_COUNT");
1478                            unsubscribe("DB_INSTRUMENT_INFO");
1479                            unsubscribe("DB_INSTRUMENTS_JOB_INFO");
1480                    }
1481            }
1482            
1483            /**
1484             * Registers the specified listener for receiving event messages.
1485             * Listeners can be registered regardless of the connection state.
1486           * @param l The <code>GlobalInfoListener</code> to register.           * @param l The <code>GlobalInfoListener</code> to register.
1487           */           */
1488          public synchronized void          public synchronized void
# Line 1227  public class Client { Line 1565  public class Client {
1565          /**          /**
1566           * Gets detailed information about a specific audio output driver.           * Gets detailed information about a specific audio output driver.
1567           * @param driverName The name of the audio output driver.           * @param driverName The name of the audio output driver.
1568           *           * @param depList An optional list of dependences parameters.
1569           * @return An <code>AudioOutputDriver</code> object containing           * @return An <code>AudioOutputDriver</code> object containing
1570           * information about the specified audio output driver.           * information about the specified audio output driver.
1571           *           *
# Line 1237  public class Client { Line 1575  public class Client {
1575           *           *
1576           * @see #getAudioOutputDriverNames           * @see #getAudioOutputDriverNames
1577           */           */
1578          private synchronized AudioOutputDriver          public synchronized AudioOutputDriver
1579          getAudioOutputDriverInfo(String driverName) throws IOException, LscpException, LSException {          getAudioOutputDriverInfo(String driverName, Parameter... depList)
1580                                            throws IOException, LscpException, LSException {
1581                    
1582                  verifyConnection();                  verifyConnection();
1583                  out.writeLine("GET AUDIO_OUTPUT_DRIVER INFO " + driverName);                  out.writeLine("GET AUDIO_OUTPUT_DRIVER INFO " + driverName);
1584                  if(getPrintOnlyMode()) return null;                  if(getPrintOnlyMode()) return null;
# Line 1248  public class Client { Line 1588  public class Client {
1588                  aod.setName(driverName);                  aod.setName(driverName);
1589                                    
1590                  for(String s : aod.getParameterNames())                  for(String s : aod.getParameterNames())
1591                          aod.addParameter(getAudioOutputDriverParameterInfo(driverName, s));                          aod.addParameter(getAudioOutputDriverParameterInfo(driverName, s, depList));
1592                                    
1593                  return aod;                  return aod;
1594          }          }
# Line 1282  public class Client { Line 1622  public class Client {
1622                  StringBuffer args = new StringBuffer(driver);                  StringBuffer args = new StringBuffer(driver);
1623                  args.append(' ').append(param);                  args.append(' ').append(param);
1624                                    
1625                  for(Parameter p : deplist)                  for(Parameter p : deplist) {
1626                            if(p == null || p.getName() == null || p.getValue() == null) continue;
1627                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
1628                    }
1629                                    
1630                  out.writeLine("GET AUDIO_OUTPUT_DRIVER_PARAMETER INFO " + args.toString());                  out.writeLine("GET AUDIO_OUTPUT_DRIVER_PARAMETER INFO " + args.toString());
1631                  if(getPrintOnlyMode()) return null;                  if(getPrintOnlyMode()) return null;
# Line 1344  public class Client { Line 1686  public class Client {
1686                  verifyConnection();                  verifyConnection();
1687                  StringBuffer args = new StringBuffer(aoDriver);                  StringBuffer args = new StringBuffer(aoDriver);
1688                                    
1689                  for(Parameter p : paramList)                  for(Parameter p : paramList) {
1690                            if(p == null || p.getName() == null || p.getValue() == null) continue;
1691                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
1692                    }
1693                                    
1694                  out.writeLine("CREATE AUDIO_OUTPUT_DEVICE " + args.toString());                  out.writeLine("CREATE AUDIO_OUTPUT_DEVICE " + args.toString());
1695                  if(getPrintOnlyMode()) return -1;                  if(getPrintOnlyMode()) return -1;
# Line 1806  public class Client { Line 2150  public class Client {
2150          /**          /**
2151           * Gets detailed information about a specific MIDI input driver.           * Gets detailed information about a specific MIDI input driver.
2152           * @param driverName The name of the MIDI input driver.           * @param driverName The name of the MIDI input driver.
2153           *           * @param depList An optional list of dependences parameters.
2154           * @return A <code>MidiInputDriver</code> object containing           * @return A <code>MidiInputDriver</code> object containing
2155           * information about the specified MIDI input driver.           * information about the specified MIDI input driver.
2156           *           *
# Line 1816  public class Client { Line 2160  public class Client {
2160           *           *
2161           * @see #getMidiInputDriverNames           * @see #getMidiInputDriverNames
2162           */           */
2163          private synchronized MidiInputDriver          public synchronized MidiInputDriver
2164          getMidiInputDriverInfo(String driverName) throws IOException, LscpException, LSException {          getMidiInputDriverInfo(String driverName, Parameter... depList)
2165                                            throws IOException, LscpException, LSException {
2166                    
2167                  verifyConnection();                  verifyConnection();
2168                  out.writeLine("GET MIDI_INPUT_DRIVER INFO " + driverName);                  out.writeLine("GET MIDI_INPUT_DRIVER INFO " + driverName);
2169                  if(getPrintOnlyMode()) return null;                  if(getPrintOnlyMode()) return null;
# Line 1828  public class Client { Line 2174  public class Client {
2174                  mid.setName(driverName);                  mid.setName(driverName);
2175                                    
2176                  for(String s : mid.getParameterNames())                  for(String s : mid.getParameterNames())
2177                          mid.addParameter(getMidiInputDriverParameterInfo(driverName, s));                          mid.addParameter(getMidiInputDriverParameterInfo(driverName, s, depList));
2178                                    
2179                  return mid;                  return mid;
2180          }          }
# Line 1862  public class Client { Line 2208  public class Client {
2208                  StringBuffer args = new StringBuffer(driver);                  StringBuffer args = new StringBuffer(driver);
2209                  args.append(' ').append(param);                  args.append(' ').append(param);
2210                                    
2211                  for(Parameter p : deplist)                  for(Parameter p : deplist) {
2212                            if(p == null || p.getName() == null || p.getValue() == null) continue;
2213                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
2214                    }
2215                                    
2216                  out.writeLine("GET MIDI_INPUT_DRIVER_PARAMETER INFO " + args.toString());                  out.writeLine("GET MIDI_INPUT_DRIVER_PARAMETER INFO " + args.toString());
2217                  if(getPrintOnlyMode()) return null;                  if(getPrintOnlyMode()) return null;
# Line 1925  public class Client { Line 2273  public class Client {
2273                  verifyConnection();                  verifyConnection();
2274                  StringBuffer args = new StringBuffer(miDriver);                  StringBuffer args = new StringBuffer(miDriver);
2275                                    
2276                  for(Parameter p : paramList)                  for(Parameter p : paramList) {
2277                            if(p == null || p.getName() == null || p.getValue() == null) continue;
2278                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());                          args.append(' ').append(p.getName()).append('=').append(p.getStringValue());
2279                    }
2280                                    
2281                  out.writeLine("CREATE MIDI_INPUT_DEVICE " + args.toString());                  out.writeLine("CREATE MIDI_INPUT_DEVICE " + args.toString());
2282                  if(getPrintOnlyMode()) return -1;                  if(getPrintOnlyMode()) return -1;
# Line 2071  public class Client { Line 2421  public class Client {
2421                                  mid.setActive(Boolean.parseBoolean(s));                                  mid.setActive(Boolean.parseBoolean(s));
2422                          } else if(s.startsWith("PORTS: ")) {                          } else if(s.startsWith("PORTS: ")) {
2423                                  s = s.substring("PORTS: ".length());                                  s = s.substring("PORTS: ".length());
2424                                  int ports = Parser.parseInt(s);                                  
2425                                  MidiPort[] midiPorts = new MidiPort[ports > 0 ? ports : 0];                                  Parameter<Integer> ports = (Parameter<Integer>)
2426                                            getMidiInputDriverParameterInfo(drv, "PORTS");
2427                                    
2428                                    ports.parseValue(s);
2429                                    mid.setPortsParameter(ports);
2430                                    
2431                                    int j = ports.getValue();
2432                                    MidiPort[] midiPorts = new MidiPort[j > 0 ? j : 0];
2433                                                                    
2434                                  for(int i = 0; i < midiPorts.length; i++)                                  for(int i = 0; i < midiPorts.length; i++)
2435                                          midiPorts[i] = getMidiInputPortInfo(deviceId, i);                                          midiPorts[i] = getMidiInputPortInfo(deviceId, i);
# Line 2315  public class Client { Line 2672  public class Client {
2672          public synchronized int          public synchronized int
2673          addMidiInstrumentMap(String name) throws IOException, LSException, LscpException {          addMidiInstrumentMap(String name) throws IOException, LSException, LscpException {
2674                  verifyConnection();                  verifyConnection();
2675                  out.writeLine("ADD MIDI_INSTRUMENT_MAP '" + name + "'");                  out.writeLine("ADD MIDI_INSTRUMENT_MAP '" + toEscapedText(name) + "'");
2676                  if(getPrintOnlyMode()) return -1;                  if(getPrintOnlyMode()) return -1;
2677                                    
2678                  ResultSet rs = getEmptyResultSet();                  ResultSet rs = getEmptyResultSet();
# Line 2418  public class Client { Line 2775  public class Client {
2775                                    
2776                  for(String s : lnS) {                  for(String s : lnS) {
2777                          if(s.startsWith("NAME: ")) {                          if(s.startsWith("NAME: ")) {
2778                                  name = s.substring("NAME: ".length());                                  name = toNonEscapedString(s.substring("NAME: ".length()));
2779                          } else if(s.startsWith("DEFAULT: ")) {                          } else if(s.startsWith("DEFAULT: ")) {
2780                                  b = Boolean.parseBoolean(s.substring("DEFAULT: ".length()));                                  b = Boolean.parseBoolean(s.substring("DEFAULT: ".length()));
2781                          } else {                          } else {
# Line 2466  public class Client { Line 2823  public class Client {
2823                                  throws IOException, LscpException, LSException {                                  throws IOException, LscpException, LSException {
2824                                    
2825                  verifyConnection();                  verifyConnection();
2826                    name = toEscapedText(name);
2827                  out.writeLine("SET MIDI_INSTRUMENT_MAP NAME " +  + mapId + " '" + name + "'");                  out.writeLine("SET MIDI_INSTRUMENT_MAP NAME " +  + mapId + " '" + name + "'");
2828                  if(getPrintOnlyMode()) return;                  if(getPrintOnlyMode()) return;
2829                                    
2830                  ResultSet rs = getEmptyResultSet();                  ResultSet rs = getEmptyResultSet();
2831          }          }
2832                    
2833            
2834            
2835          /**          /**
2836           * Creates or replaces a MIDI instrument map entry.           * Creates or replaces a MIDI instrument map entry.
2837           * @param mapId The ID of the map, where this instrument should be mapped.           * @param mapId The ID of the map, where this instrument should be mapped.
# Line 2486  public class Client { Line 2846  public class Client {
2846          public synchronized void          public synchronized void
2847          mapMidiInstrument(int mapId, MidiInstrumentEntry entry, MidiInstrumentInfo info)          mapMidiInstrument(int mapId, MidiInstrumentEntry entry, MidiInstrumentInfo info)
2848                                          throws IOException, LSException, LscpException {                                          throws IOException, LSException, LscpException {
2849                    mapMidiInstrument(mapId, entry, info, false);
2850            }
2851            
2852            /**
2853             * Creates or replaces a MIDI instrument map entry.
2854             * @param mapId The ID of the map, where this instrument should be mapped.
2855             * @param entry Specifies the position of the MIDI instrument in the MIDI instrument map.
2856             * @param info Provides the needed information of the
2857             * MIDI instrument, which will be mapped to the specified MIDI instrument map.
2858             * @param nonModal If <code>true</code> the function returns immediately
2859             * and the mapping is established in the background.
2860             * @throws IOException If some I/O error occurs.
2861             * @throws LSException If the mapping failed.
2862             * @throws LscpException If LSCP protocol corruption occurs.
2863             * @see #unmapMidiInstrument
2864             */
2865            public synchronized void
2866            mapMidiInstrument(int mapId, MidiInstrumentEntry entry, MidiInstrumentInfo info, boolean nonModal)
2867                                            throws IOException, LSException, LscpException {
2868                                    
2869                  verifyConnection();                  verifyConnection();
2870                  StringBuffer cmd = new StringBuffer("MAP MIDI_INSTRUMENT ");                  StringBuffer cmd = new StringBuffer("MAP MIDI_INSTRUMENT ");
2871                    if(nonModal) cmd.append("NON_MODAL ");
2872                  cmd.append(mapId).append(' ');                  cmd.append(mapId).append(' ');
2873                  cmd.append(entry.getMidiBank()).append(' ');                  cmd.append(entry.getMidiBank()).append(' ');
2874                  cmd.append(entry.getMidiProgram()).append(' ');                  cmd.append(entry.getMidiProgram()).append(' ');
2875                  cmd.append(info.getEngine()).append(" '");                  cmd.append(info.getEngine()).append(" '");
2876                  cmd.append(info.getFileName()).append("' ");                  cmd.append(conv(info.getFilePath())).append("' ");
2877                  cmd.append(info.getInstrumentIndex()).append(' ');                  cmd.append(info.getInstrumentIndex()).append(' ');
2878                  cmd.append(info.getVolume());                  cmd.append(info.getVolume());
2879                  if(!info.getLoadMode().name().equals("DEFAULT")) {                  if(!info.getLoadMode().name().equals("DEFAULT")) {
2880                          cmd.append(' ').append(info.getLoadMode().name());                          cmd.append(' ').append(info.getLoadMode().name());
2881                  }                  }
2882                  if(info.getName() != null) cmd.append(" '").append(info.getName()).append("'");                  
2883                    if(info.getName() != null) {
2884                            String s = toEscapedText(info.getName());
2885                            cmd.append(" '").append(s).append("'");
2886                    }
2887                                    
2888                  out.writeLine(cmd.toString());                  out.writeLine(cmd.toString());
2889                  if(getPrintOnlyMode()) return;                  if(getPrintOnlyMode()) return;
# Line 2588  public class Client { Line 2972  public class Client {
2972          }          }
2973                    
2974          /**          /**
2975           * Gets all MIDI instrument contained int the specified MIDI instrument map.           * Gets all MIDI instrument entries contained int the specified MIDI instrument map.
2976             * @param mapId The ID of the map, which instruments should be obtained.
2977             * @return An int array providing all MIDI instrument entries
2978             * in the specified MIDI instrument map.
2979             * @throws IOException If some I/O error occurs.
2980             * @throws LscpException If LSCP protocol corruption occurs.
2981             * @throws LSException If some other error occurs.
2982             */
2983            public synchronized int[][]
2984            getMidiInstrumentEntries(int mapId) throws IOException, LscpException, LSException {
2985                    verifyConnection();
2986                    out.writeLine("LIST MIDI_INSTRUMENTS " + String.valueOf(mapId));
2987                    if(getPrintOnlyMode()) return null;
2988                    
2989                    String[] entries = parseArray(getSingleLineResultSet().getResult());
2990                    int[][] e = new int[entries.length][3];
2991                    
2992                    for(int i = 0; i < entries.length; i++) {
2993                            Integer[] vals = parseIntList(entries[i]);
2994                            if(vals.length != 3) {
2995                                    throw new LscpException(LscpI18n.getLogMsg("CommandFailed!"));
2996                            }
2997                            
2998                            e[i][0] = vals[0];
2999                            e[i][1] = vals[1];
3000                            e[i][2] = vals[2];
3001                    }
3002                    
3003                    return e;
3004            }
3005            
3006            /**
3007             * Gets all MIDI instruments contained int the specified MIDI instrument map.
3008           * @param mapId The ID of the map, which instruments should be obtained.           * @param mapId The ID of the map, which instruments should be obtained.
3009           * @return A <code>MidiInstrumentInfo</code> array providing           * @return A <code>MidiInstrumentInfo</code> array providing
3010           * all MIDI instruments from all MIDI instrument maps.           * all MIDI instruments in the specified MIDI instrument map.
3011           * @throws IOException If some I/O error occurs.           * @throws IOException If some I/O error occurs.
3012           * @throws LscpException If LSCP protocol corruption occurs.           * @throws LscpException If LSCP protocol corruption occurs.
3013           * @throws LSException If some other error occurs.           * @throws LSException If some other error occurs.
# Line 2639  public class Client { Line 3055  public class Client {
3055                                          throws IOException, LscpException, LSException {                                          throws IOException, LscpException, LSException {
3056                    
3057                  verifyConnection();                  verifyConnection();
3058                    requestMidiInstrumentInfo(mapId, bank, program);
3059                    return getMidiInstrumentInfoResponse(mapId, bank, program);
3060            }
3061            
3062            private void
3063            requestMidiInstrumentInfo(int mapId, int bank, int program) throws IOException {
3064                  StringBuffer cmd = new StringBuffer("GET MIDI_INSTRUMENT INFO ");                  StringBuffer cmd = new StringBuffer("GET MIDI_INSTRUMENT INFO ");
3065                  cmd.append(mapId).append(' ');                  cmd.append(mapId).append(' ');
3066                  cmd.append(bank).append(' ');                  cmd.append(bank).append(' ');
3067                  cmd.append(program);                  cmd.append(program);
3068                                    
3069                  out.writeLine(cmd.toString());                  out.writeLine(cmd.toString());
3070                  if(getPrintOnlyMode()) return null;          }
3071            
3072            private MidiInstrumentInfo
3073            getMidiInstrumentInfoResponse(int mapId, int bank, int program)
3074                                            throws IOException, LscpException, LSException {
3075                                    
3076                    if(getPrintOnlyMode()) return null;
3077                  ResultSet rs = getMultiLineResultSet();                  ResultSet rs = getMultiLineResultSet();
3078                  MidiInstrumentEntry entry = new MidiInstrumentEntry(bank, program);                  MidiInstrumentEntry entry = new MidiInstrumentEntry(bank, program);
3079                  return new MidiInstrumentInfo(mapId, entry, rs.getMultiLineResult());                  return new MidiInstrumentInfo(mapId, entry, rs.getMultiLineResult());
# Line 2696  public class Client { Line 3123  public class Client {
3123                                                  throws IOException, LscpException, LSException {                                                  throws IOException, LscpException, LSException {
3124                                    
3125                  String cmd = nonModal ? "LOAD INSTRUMENT NON_MODAL " : "LOAD INSTRUMENT ";                  String cmd = nonModal ? "LOAD INSTRUMENT NON_MODAL " : "LOAD INSTRUMENT ";
3126                  String args = '\'' + filename + "' " + instrIdx + ' ' + samplerChn;                  String args = '\'' + conv(filename) + "' " + instrIdx + ' ' + samplerChn;
3127                                    
3128                  out.writeLine(cmd + args);                  out.writeLine(cmd + args);
3129                  if(getPrintOnlyMode()) return;                  if(getPrintOnlyMode()) return;
# Line 3348  public class Client { Line 3775  public class Client {
3775                                    
3776                  verifyConnection();                  verifyConnection();
3777                  String s = String.valueOf(channel) + " " + String.valueOf(midiCtrl);                  String s = String.valueOf(channel) + " " + String.valueOf(midiCtrl);
3778                  if(name != null) s += " '" + name + "'";                  if(name != null) s += " '" + toEscapedText(name) + "'";
3779                  out.writeLine("CREATE FX_SEND " + s);                  out.writeLine("CREATE FX_SEND " + s);
3780                  if(getPrintOnlyMode()) return -1;                  if(getPrintOnlyMode()) return -1;
3781                                    
# Line 3479  public class Client { Line 3906  public class Client {
3906                                  throws IOException, LscpException, LSException {                                  throws IOException, LscpException, LSException {
3907                                    
3908                  verifyConnection();                  verifyConnection();
3909                  String args = " " + channel + " " + fxSend + " '" + name + "'";                  String args = " " + channel + " " + fxSend + " '" + toEscapedText(name) + "'";
3910                  out.writeLine("SET FX_SEND NAME" + args);                  out.writeLine("SET FX_SEND NAME" + args);
3911                  if(getPrintOnlyMode()) return;                  if(getPrintOnlyMode()) return;
3912                                    
# Line 3568  public class Client { Line 3995  public class Client {
3995          }          }
3996                    
3997          /**          /**
3998             * Starts an instrument editor for editing the loaded instrument
3999             * on the specified sampler channel.
4000             * @param samplerChn The sampler channel number.
4001             * @throws IOException If some I/O error occurs.
4002             * @throws LscpException If LSCP protocol corruption occurs.
4003             * @throws LSException If <code>samplerChn</code> is not a valid channel number or if
4004             * there is no instrument loaded on the specified sampler channel.
4005             * @see #getSamplerChannels
4006             */
4007            public synchronized void
4008            editChannelInstrument(int samplerChn) throws IOException, LscpException, LSException {
4009                    verifyConnection();
4010                    out.writeLine("EDIT CHANNEL INSTRUMENT " + samplerChn);
4011                    if(getPrintOnlyMode()) return;
4012                    
4013                    ResultSet rs = getEmptyResultSet();
4014            }
4015            
4016            
4017            
4018            /**
4019             * Adds the specified directory to the instruments database.
4020             * @param dir The absolute (escaped) path name of the directory to add.
4021             * @throws IOException If some I/O error occurs.
4022             * @throws LSException If the creation of the directory failed.
4023             * @throws LscpException If LSCP protocol corruption occurs.
4024             */
4025            public synchronized void
4026            addDbDirectory(String dir) throws IOException, LSException, LscpException {
4027                    verifyConnection();
4028                    out.writeLine("ADD DB_INSTRUMENT_DIRECTORY '" + conv(dir) + "'");
4029                    if(getPrintOnlyMode()) return;
4030                    
4031                    ResultSet rs = getEmptyResultSet();
4032            }
4033            
4034            /**
4035             * Removes the specified directory from the instruments database.
4036             * @param dir The absolute (escaped) path name of the directory to remove.
4037             * @throws IOException If some I/O error occurs.
4038             * @throws LscpException If LSCP protocol corruption occurs.
4039             * @throws LSException If the specified directory is not
4040             * empty or if the removal of the directory failed.
4041             */
4042            public synchronized void
4043            removeDbDirectory(String dir) throws IOException, LscpException, LSException {
4044                    removeDbDirectory(dir, false);
4045            }
4046            
4047            /**
4048             * Removes the specified directory from the instruments database.
4049             * @param dir The absolute path name of the directory to remove.
4050             * @param force If <code>true</code> forces the removal of non-empty
4051             * directory and all its content.
4052             * @throws IOException If some I/O error occurs.
4053             * @throws LscpException If LSCP protocol corruption occurs.
4054             * @throws LSException If the removing of the directory failed.
4055             */
4056            public synchronized void
4057            removeDbDirectory(String dir, boolean force)
4058                                    throws IOException, LscpException, LSException {
4059                    
4060                    verifyConnection();
4061                    String s = "REMOVE DB_INSTRUMENT_DIRECTORY ";
4062                    if(force) s += "FORCE ";
4063                    out.writeLine(s + "'" + conv(dir) + "'");
4064                    if(getPrintOnlyMode()) return;
4065                    
4066                    ResultSet rs = getEmptyResultSet();
4067            }
4068            
4069            /**
4070             * Removes the specified directories from the instruments database.
4071             * @param dirs The absolute (escaped) path names of the directories to remove.
4072             * @param force If <code>true</code> forces the removal of non-empty
4073             * directories.
4074             * @throws IOException If some I/O error occurs.
4075             * @throws LscpException If LSCP protocol corruption occurs.
4076             * @throws LSException If the removing of the directores failed.
4077             */
4078            public synchronized void
4079            removeDbDirectories(String[] dirs, boolean force)
4080                                    throws IOException, LscpException, LSException {
4081                    
4082                    verifyConnection();
4083                    String cmd = "REMOVE DB_INSTRUMENT_DIRECTORY ";
4084                    if(force) cmd += "FORCE ";
4085                    
4086                    for(String s : dirs) out.writeLine(cmd + "'" + conv(s) + "'");
4087                    
4088                    if(getPrintOnlyMode()) return;
4089                    
4090                    getEmptyResultSets(dirs.length, "Client.dirDeletionFailed!");
4091            }
4092            
4093            /**
4094             * Gets the number of directories in the specified directory.
4095             * @return The current number of directories in the specified directory.
4096             * @param dir The absolute path name of the directory.
4097             * @throws IOException If some I/O error occurs.
4098             * @throws LscpException If LSCP protocol corruption occurs.
4099             * @throws LSException If some other error occurs.
4100             */
4101            public synchronized int
4102            getDbDirectoryCount(String dir) throws IOException, LscpException, LSException {
4103                    return getDbDirectoryCount(dir, false);
4104            }
4105            
4106            /**
4107             * Gets the number of directories in the specified directory.
4108             * @return The current number of directories in the specified directory.
4109             * @param dir The absolute path name of the directory.
4110             * @param recursive If <code>true</code>, the number of all directories
4111             * in the specified subtree will be returned.
4112             * @throws IOException If some I/O error occurs.
4113             * @throws LscpException If LSCP protocol corruption occurs.
4114             * @throws LSException If some other error occurs.
4115             */
4116            public synchronized int
4117            getDbDirectoryCount(String dir, boolean recursive)
4118                                    throws IOException, LscpException, LSException {
4119                    
4120                    verifyConnection();
4121                    String s;
4122                    if(recursive) s = "GET DB_INSTRUMENT_DIRECTORIES RECURSIVE '";
4123                    else s = "GET DB_INSTRUMENT_DIRECTORIES '";
4124                    out.writeLine(s + conv(dir) + "'");
4125                    if(getPrintOnlyMode()) return -1;
4126                    
4127                    s = getSingleLineResultSet().getResult();
4128                    return parseInt(s);
4129            }
4130            
4131            /**
4132             * Gets the list of directories in the specified directory.
4133             * @param dir The absolute path name of the directory.
4134             * @return A <code>String</code> array providing the names of
4135             * all directories in the specified directory.
4136             * @throws IOException If some I/O error occurs.
4137             * @throws LscpException If LSCP protocol corruption occurs.
4138             * @throws LSException If the specified path name is invalid.
4139             */
4140            public synchronized String[]
4141            getDbDirectoryNames(String dir) throws IOException, LscpException, LSException {
4142                    verifyConnection();
4143                    out.writeLine("LIST DB_INSTRUMENT_DIRECTORIES '" + conv(dir) + "'");
4144                    if(getPrintOnlyMode()) return null;
4145                    
4146                    String[] names = parseEscapedStringList(getSingleLineResultSet().getResult());
4147                    for(int i = 0; i < names.length; i++) {
4148                            names[i] = toNonEscapedString(names[i]);
4149                    }
4150                    return names;
4151            }
4152            
4153            /**
4154             * Gets information about the specified directory.
4155             * @param dir The absolute path name of the directory.
4156             * @return A <code>DbDirectoryInfo</code> instance providing information
4157             * about the specified directory.
4158             * @throws IOException If some I/O error occurs.
4159             * @throws LscpException If LSCP protocol corruption occurs.
4160             * @throws LSException If the specified directory is not found.
4161             */
4162            public synchronized DbDirectoryInfo
4163            getDbDirectoryInfo(String dir) throws IOException, LscpException, LSException {
4164                    verifyConnection();
4165                    out.writeLine("GET DB_INSTRUMENT_DIRECTORY INFO '" + conv(dir) + "'");
4166                    if(getPrintOnlyMode()) return null;
4167                    
4168                    ResultSet rs = getMultiLineResultSet();
4169                    DbDirectoryInfo info = new DbDirectoryInfo(rs.getMultiLineResult());
4170                    if(dir.equals("/")) {
4171                            info.setName("/");
4172                    } else {
4173                            dir = removeEndingFileSeparator(dir);
4174                    }
4175                    String s = getFileName(dir);
4176                    if(s != null) info.setName(toNonEscapedFileName(s));
4177                    s = getParentDirectory(dir);
4178                    if(s != null) info.setParentDirectoryPath(s);
4179                    
4180                    return info;
4181            }
4182            
4183            /**
4184             * Gets the list of directories in the specified directory.
4185             * @param dir The absolute path name of the directory.
4186             * @return A <code>DbDirectoryInfo</code> array providing
4187             * information about all directories in the specified directory.
4188             * @throws IOException If some I/O error occurs.
4189             * @throws LscpException If LSCP protocol corruption occurs.
4190             * @throws LSException If the specified path name is invalid.
4191             */
4192            public synchronized DbDirectoryInfo[]
4193            getDbDirectories(String dir) throws IOException, LscpException, LSException {
4194                    String[] dirS = getDbDirectoryNames(dir);
4195                    if(!hasEndingFileSeparator(dir)) dir += "/";
4196                    DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length];
4197                    for(int i = 0; i < dirS.length; i++) {
4198                            infoS[i] = getDbDirectoryInfo(conv(dir) + toEscapedFsEntry(dirS[i]));
4199                    }
4200                    return infoS;
4201            }
4202            
4203            /**
4204             * Gets the list of directories in the specified directory.
4205             * @param dir The absolute path name of the directory.
4206             * @return A <code>DbDirectoryInfo</code> array providing
4207             * information about all directories in the specified directory.
4208             * @throws IOException If some I/O error occurs.
4209             * @throws LscpException If LSCP protocol corruption occurs.
4210             * @throws LSException If the specified path name is invalid.
4211             *
4212            public synchronized DbDirectoryInfo[]
4213            getDbDirectories(String dir) throws IOException, LscpException, LSException {
4214                    String[] dirS = getDbDirectoryNames(conv(dir));
4215                    if(dirS.length == 0) return new DbDirectoryInfo[0];
4216                    
4217                    if(dir.charAt(dir.length() - 1) != '/') dir += "/"; // FIXME:
4218                    
4219                    for(int i = 0; i < dirS.length; i++) {
4220                            out.writeLine("GET DB_INSTRUMENT_DIRECTORY INFO '" + conv(dir + dirS[i]) + "'");
4221                    }
4222                    
4223                    if(getPrintOnlyMode()) return null;
4224                    
4225                    if(dir.length() > 1) dir = dir.substring(0, dir.length() - 1);
4226                    StringBuffer sb = new StringBuffer();
4227                    DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length];
4228                    for(int i = 0; i < dirS.length; i++) {
4229                            try {
4230                                    ResultSet rs = getMultiLineResultSet();
4231                                    infoS[i] = new DbDirectoryInfo(rs.getMultiLineResult());
4232                                    infoS[i].setName(dirS[i]);
4233                                    infoS[i].setParentDirectoryPath(dir);
4234                            } catch (SocketTimeoutException e) {
4235                                    getLogger().log(Level.FINE, e.getMessage(), e);
4236                                    sb.append(e.getMessage()).append("\n");
4237                                    break;
4238                            } catch (Exception e) {
4239                                    getLogger().log(Level.FINE, e.getMessage(), e);
4240                                    sb.append(e.getMessage()).append("\n");
4241                            }
4242                    }
4243                    
4244                    String details = sb.toString();
4245                    if(details.length() > 0) {
4246                            String err = LscpI18n.getLogMsg("Client.getInstrsInfoFailed!");
4247                            throw new LSException(0, err, details);
4248                    }
4249                    
4250                    return infoS;
4251            }*/
4252            
4253            /**
4254             * Renames the specified directory.
4255             * @param dir The absolute path name of the directory to rename.
4256             * @param name The new name for the directory.
4257             * @throws IOException If some I/O error occurs.
4258             * @throws LSException If the renaming of the directory failed.
4259             * @throws LscpException If LSCP protocol corruption occurs.
4260             */
4261            public synchronized void
4262            renameDbDirectory(String dir, String name) throws IOException, LSException, LscpException {
4263                    verifyConnection();
4264                    name = toEscapedText(name);
4265                    out.writeLine("SET DB_INSTRUMENT_DIRECTORY NAME '" + conv(dir) + "' '" + conv(name) + "'");
4266                    if(getPrintOnlyMode()) return;
4267                    
4268                    ResultSet rs = getEmptyResultSet();
4269            }
4270            
4271            /**
4272             * Moves the specified directory into the specified location.
4273             * @param dir The absolute path name of the directory to move.
4274             * @param dst The location where the directory will be moved to.
4275             * @throws IOException If some I/O error occurs.
4276             * @throws LSException If the operation failed.
4277             * @throws LscpException If LSCP protocol corruption occurs.
4278             */
4279            public synchronized void
4280            moveDbDirectory(String dir, String dst) throws IOException, LSException, LscpException {
4281                    verifyConnection();
4282                    out.writeLine("MOVE DB_INSTRUMENT_DIRECTORY '" + conv(dir) + "' '" + conv(dst) + "'");
4283                    if(getPrintOnlyMode()) return;
4284                    
4285                    ResultSet rs = getEmptyResultSet();
4286            }
4287            
4288            /**
4289             * Moves the specified directories into the specified location.
4290             * @param dirs The absolute path names of the directories to move.
4291             * @param dst The location where the directories will be moved to.
4292             * @throws IOException If some I/O error occurs.
4293             * @throws LSException If the operation failed.
4294             * @throws LscpException If LSCP protocol corruption occurs.
4295             */
4296            public synchronized void
4297            moveDbDirectories(String dirs[], String dst) throws IOException, LSException, LscpException {
4298                    verifyConnection();
4299                    for(String s : dirs) {
4300                            out.writeLine("MOVE DB_INSTRUMENT_DIRECTORY '" + conv(s) + "' '" + conv(dst) + "'");
4301                    }
4302                    if(getPrintOnlyMode()) return;
4303                    
4304                    getEmptyResultSets(dirs.length, "Client.dirMovingFailed!");
4305            }
4306            
4307            /**
4308             * Copies the specified directory into the specified location.
4309             * @param dir The absolute path name of the directory to copy.
4310             * @param dst The location where the directory will be copied to.
4311             * @throws IOException If some I/O error occurs.
4312             * @throws LSException If the operation failed.
4313             * @throws LscpException If LSCP protocol corruption occurs.
4314             */
4315            public synchronized void
4316            copyDbDirectory(String dir, String dst) throws IOException, LSException, LscpException {
4317                    verifyConnection();
4318                    out.writeLine("COPY DB_INSTRUMENT_DIRECTORY '" + conv(dir) + "' '" + conv(dst) + "'");
4319                    if(getPrintOnlyMode()) return;
4320                    
4321                    ResultSet rs = getEmptyResultSet();
4322            }
4323            
4324            /**
4325             * Copies the specified directories into the specified location.
4326             * @param dirs The absolute path names of the directories to copy.
4327             * @param dst The location where the directories will be copied to.
4328             * @throws IOException If some I/O error occurs.
4329             * @throws LSException If the operation failed.
4330             * @throws LscpException If LSCP protocol corruption occurs.
4331             */
4332            public synchronized void
4333            copyDbDirectories(String[] dirs, String dst) throws IOException, LSException, LscpException {
4334                    verifyConnection();
4335                    for(String s : dirs) {
4336                            out.writeLine("COPY DB_INSTRUMENT_DIRECTORY '" + conv(s) + "' '" + conv(dst) + "'");
4337                    }
4338                    if(getPrintOnlyMode()) return;
4339                    
4340                    getEmptyResultSets(dirs.length, "Client.dirCopyingFailed!");
4341            }
4342            
4343            /**
4344             * Changes the description of the specified directory.
4345             * @param dir The absolute path name of the directory.
4346             * @param desc The new description for the directory.
4347             * @throws IOException If some I/O error occurs.
4348             * @throws LSException If failed to change the description.
4349             * @throws LscpException If LSCP protocol corruption occurs.
4350             */
4351            public synchronized void
4352            setDbDirectoryDescription(String dir, String desc)
4353                                    throws IOException, LSException, LscpException {
4354                    
4355                    verifyConnection();
4356                    String s = "SET DB_INSTRUMENT_DIRECTORY DESCRIPTION '";
4357                    out.writeLine(s + conv(dir) + "' '" + toEscapedText(desc) + "'");
4358                    if(getPrintOnlyMode()) return;
4359                    
4360                    ResultSet rs = getEmptyResultSet();
4361            }
4362            
4363            public static enum ScanMode {
4364                    RECURSIVE, NON_RECURSIVE, FLAT
4365            }
4366            
4367            /**
4368             * Adds the specified instrument to the specified instruments database directory.
4369             * @param dbDir The absolute path name of the database directory in which the
4370             * specified instrument will be added.
4371             * @param filePath The absolute path name of the instrument file.
4372             * @param instrIndex The index of the instrument (in the given instrument file) to add.
4373             * @throws IOException If some I/O error occurs.
4374             * @throws LSException If the operation failed.
4375             * @throws LscpException If LSCP protocol corruption occurs.
4376             */
4377            public synchronized void
4378            addDbInstrument(String dbDir, String filePath, int instrIndex)
4379                                            throws IOException, LSException, LscpException {
4380                    
4381                    addDbInstrument(dbDir, filePath, instrIndex, false);
4382            }
4383            
4384            /**
4385             * Adds the specified instrument to the specified instruments database directory.
4386             * @param dbDir The absolute path name of the database directory in which the
4387             * specified instrument will be added.
4388             * @param filePath The absolute path name of the instrument file.
4389             * @param instrIndex The index of the instrument (in the given instrument file) to add.
4390             * @param background If <code>true</code>, the scan will be done
4391             * in background and this method may return before the job is finished.
4392             * @return If <code>background</code> is <code>true</code>, the ID
4393             * of the scan job.
4394             * @throws IOException If some I/O error occurs.
4395             * @throws LSException If the operation failed.
4396             * @throws LscpException If LSCP protocol corruption occurs.
4397             * @see #addInstrumentsDbListener
4398             */
4399            public synchronized int
4400            addDbInstrument(String dbDir, String filePath, int instrIndex, boolean background)
4401                                            throws IOException, LSException, LscpException {
4402                    
4403                    verifyConnection();
4404                    String s = "ADD DB_INSTRUMENTS";
4405                    if(background) s += " NON_MODAL";
4406                    s += " '" + conv(dbDir) + "' '" + conv(filePath) + "' ";
4407                    out.writeLine(s + String.valueOf(instrIndex));
4408                    if(getPrintOnlyMode()) return -1;
4409                    
4410                    ResultSet rs = getEmptyResultSet();
4411                    return rs.getIndex();
4412            }
4413            
4414            /**
4415             * Adds the instruments in the specified file to the specified
4416             * instruments database directory.
4417             * @param dbDir The absolute path name of the database directory
4418             * in which the the supported instruments will be added.
4419             * @param filePath The absolute path name of the file to scan for instruments.
4420             * @throws IOException If some I/O error occurs.
4421             * @throws LSException If the operation failed.
4422             * @throws LscpException If LSCP protocol corruption occurs.
4423             */
4424            public synchronized void
4425            addDbInstruments(String dbDir, String filePath)
4426                                            throws IOException, LSException, LscpException {
4427                    
4428                    addDbInstruments(dbDir, filePath, false);
4429            }
4430            
4431            /**
4432             * Adds the instruments in the specified file to the specified
4433             * instruments database directory.
4434             * @param dbDir The absolute path name of the database directory
4435             * in which the the supported instruments will be added.
4436             * @param filePath The absolute path name of the file to scan for instruments.
4437             * @param background If <code>true</code>, the scan will be done
4438             * in background and this method may return before the job is finished.
4439             * @return If <code>background</code> is <code>true</code>, the ID
4440             * of the scan job.
4441             * @throws IOException If some I/O error occurs.
4442             * @throws LSException If the operation failed.
4443             * @throws LscpException If LSCP protocol corruption occurs.
4444             * @see #addInstrumentsDbListener
4445             */
4446            public synchronized int
4447            addDbInstruments(String dbDir, String filePath, boolean background)
4448                                            throws IOException, LSException, LscpException {
4449                    
4450                    verifyConnection();
4451                    String s = "ADD DB_INSTRUMENTS";
4452                    if(background) s += " NON_MODAL";
4453                    out.writeLine(s + " '" + conv(dbDir) + "' '" + conv(filePath) + "'");
4454                    if(getPrintOnlyMode()) return -1;
4455                    
4456                    ResultSet rs = getEmptyResultSet();
4457                    return rs.getIndex();
4458            }
4459            
4460            /**
4461             * Adds the instruments in the specified file system directory
4462             * to the specified instruments database directory.
4463             * @param mode Determines the scanning mode. If RECURSIVE is
4464             * specified, all supported instruments in the specified file system
4465             * direcotry will be added to the specified instruments database
4466             * directory, including the instruments in subdirectories
4467             * of the supplied directory. If NON_RECURSIVE is specified,
4468             * the instruments in the subdirectories will not be processed.
4469             * If FLAT is specified, all supported instruments in the specified
4470             * file system direcotry will be added, including the instruments in
4471             * subdirectories of the supplied directory, but the respective
4472             * subdirectory structure will not be recreated in the instruments
4473             * database and all instruments will be added directly in the
4474             * specified database directory.
4475             * @param dbDir The absolute path name of the database directory
4476             * in which the supported instruments will be added.
4477             * @param fsDir The absolute path name of the file system directory.
4478             * @throws IOException If some I/O error occurs.
4479             * @throws LSException If the operation failed.
4480             * @throws LscpException If LSCP protocol corruption occurs.
4481             */
4482            public synchronized void
4483            addDbInstruments(ScanMode mode, String dbDir, String fsDir)
4484                                            throws IOException, LSException, LscpException {
4485                    
4486                    addDbInstruments(mode, dbDir, fsDir, false);
4487            }
4488            
4489            /**
4490             * Adds the instruments in the specified file system directory
4491             * to the specified instruments database directory.
4492             * @param mode Determines the scanning mode. If RECURSIVE is
4493             * specified, all supported instruments in the specified file system
4494             * direcotry will be added to the specified instruments database
4495             * directory, including the instruments in subdirectories
4496             * of the supplied directory. If NON_RECURSIVE is specified,
4497             * the instruments in the subdirectories will not be processed.
4498             * If FLAT is specified, all supported instruments in the specified
4499             * file system direcotry will be added, including the instruments in
4500             * subdirectories of the supplied directory, but the respective
4501             * subdirectory structure will not be recreated in the instruments
4502             * database and all instruments will be added directly in the
4503             * specified database directory.
4504             * @param dbDir The absolute path name of the database directory
4505             * in which the supported instruments will be added.
4506             * @param fsDir The absolute path name of the file system directory.
4507             * @param background If <code>true</code>, the scan will be done
4508             * in background and this method may return before the job is finished.
4509             * @return If <code>background</code> is <code>true</code>, the ID
4510             * of the scan job.
4511             * @throws IOException If some I/O error occurs.
4512             * @throws LSException If the operation failed.
4513             * @throws LscpException If LSCP protocol corruption occurs.
4514             * @see #addInstrumentsDbListener
4515             */
4516            public synchronized int
4517            addDbInstruments(ScanMode mode, String dbDir, String fsDir, boolean background)
4518                                            throws IOException, LSException, LscpException {
4519                    
4520                    verifyConnection();
4521                    StringBuffer sb = new StringBuffer("ADD DB_INSTRUMENTS");
4522                    if(background) sb.append(" NON_MODAL");
4523                    
4524                    switch(mode) {
4525                            case RECURSIVE:
4526                                    sb.append(" RECURSIVE");
4527                                    break;
4528                            case NON_RECURSIVE:
4529                                    sb.append(" NON_RECURSIVE");
4530                                    break;
4531                            case FLAT:
4532                                    sb.append(" FLAT");
4533                                    break;
4534                    }
4535                    
4536                    sb.append(" '").append(conv(dbDir)).append("' '");
4537                    sb.append(conv(fsDir)).append("'");
4538                    out.writeLine(sb.toString());
4539                    if(getPrintOnlyMode()) return -1;
4540                    
4541                    ResultSet rs = getEmptyResultSet();
4542                    return rs.getIndex();
4543            }
4544            
4545            /**
4546             * Removes the specified instrument from the instruments database.
4547             * @param instr The absolute path name of the instrument to remove.
4548             * @throws IOException If some I/O error occurs.
4549             * @throws LscpException If LSCP protocol corruption occurs.
4550             * @throws LSException If the removing of the instrument failed.
4551             */
4552            public synchronized void
4553            removeDbInstrument(String instr) throws IOException, LscpException, LSException {
4554                    
4555                    verifyConnection();
4556                    out.writeLine("REMOVE DB_INSTRUMENT '" + conv(instr) + "'");
4557                    if(getPrintOnlyMode()) return;
4558                    
4559                    ResultSet rs = getEmptyResultSet();
4560            }
4561            
4562            /**
4563             * Removes the specified instruments from the instruments database.
4564             * @param instrs The absolute path names of the instruments to remove.
4565             * @throws IOException If some I/O error occurs.
4566             * @throws LscpException If LSCP protocol corruption occurs.
4567             * @throws LSException If the removing of the instruments failed.
4568             */
4569            public synchronized void
4570            removeDbInstruments(String[] instrs) throws IOException, LscpException, LSException {
4571                    verifyConnection();
4572                    for(String s : instrs) {
4573                            out.writeLine("REMOVE DB_INSTRUMENT '" + conv(s) + "'");
4574                    }
4575                    if(getPrintOnlyMode()) return;
4576                    
4577                    getEmptyResultSets(instrs.length, "Client.instrDeletionFailed!");
4578            }
4579            
4580            /**
4581             * Gets the number of instruments in the specified directory.
4582             * @return The current number of instruments in the specified directory.
4583             * @param dir The absolute path name of the directory.
4584             * @throws IOException If some I/O error occurs.
4585             * @throws LscpException If LSCP protocol corruption occurs.
4586             * @throws LSException If some other error occurs.
4587             */
4588            public synchronized int
4589            getDbInstrumentCount(String dir) throws IOException, LscpException, LSException {
4590                    return getDbInstrumentCount(dir, false);
4591            }
4592            
4593            /**
4594             * Gets the number of instruments in the specified directory.
4595             * @return The current number of instruments in the specified directory.
4596             * @param dir The absolute path name of the directory.
4597             * @param recursive If <code>true</code>, the number of all instruments
4598             * in the specified subtree will be returned.
4599             * @throws IOException If some I/O error occurs.
4600             * @throws LscpException If LSCP protocol corruption occurs.
4601             * @throws LSException If some other error occurs.
4602             */
4603            public synchronized int
4604            getDbInstrumentCount(String dir, boolean recursive)
4605                                    throws IOException, LscpException, LSException {
4606                    
4607                    verifyConnection();
4608                    String s;
4609                    if(recursive) s = "GET DB_INSTRUMENTS RECURSIVE '";
4610                    else s = "GET DB_INSTRUMENTS '";
4611                    out.writeLine(s + conv(dir) + "'");
4612                    if(getPrintOnlyMode()) return -1;
4613                    
4614                    s = getSingleLineResultSet().getResult();
4615                    return parseInt(s);
4616            }
4617            
4618            /**
4619             * Gets the list of instruments in the specified directory.
4620             * @param dir The absolute path name of the directory.
4621             * @return A <code>String</code> array providing the names of
4622             * all instruments in the specified directory.
4623             * @throws IOException If some I/O error occurs.
4624             * @throws LscpException If LSCP protocol corruption occurs.
4625             * @throws LSException If the specified path name is invalid.
4626             */
4627            public synchronized String[]
4628            getDbInstrumentNames(String dir) throws IOException, LscpException, LSException {
4629                    verifyConnection();
4630                    out.writeLine("LIST DB_INSTRUMENTS '" + conv(dir) + "'");
4631                    if(getPrintOnlyMode()) return null;
4632                    
4633                    String[] names = parseEscapedStringList(getSingleLineResultSet().getResult());
4634                    for(int i = 0; i < names.length; i++) {
4635                            names[i] = toNonEscapedString(names[i]);
4636                    }
4637                    return names;
4638            }
4639            
4640            /**
4641             * Gets information about the specified instrument.
4642             * @param instr The absolute path name of the instrument.
4643             * @return A <code>DbInstrumentInfo</code> instance providing information
4644             * about the specified instrument.
4645             * @throws IOException If some I/O error occurs.
4646             * @throws LscpException If LSCP protocol corruption occurs.
4647             * @throws LSException If the specified instrument is not found.
4648             */
4649            public synchronized DbInstrumentInfo
4650            getDbInstrumentInfo(String instr) throws IOException, LscpException, LSException {
4651                    verifyConnection();
4652                    out.writeLine("GET DB_INSTRUMENT INFO '" + conv(instr) + "'");
4653                    if(getPrintOnlyMode()) return null;
4654                    
4655                    ResultSet rs = getMultiLineResultSet();
4656                    DbInstrumentInfo info = new DbInstrumentInfo(rs.getMultiLineResult());
4657                    String s = getParentDirectory(instr);
4658                    if(s != null) info.setDirectoryPath(s);
4659                    s = getFileName(instr);
4660                    if(s != null) info.setName(toNonEscapedFileName(s));
4661                    
4662                    return info;
4663            }
4664            
4665            /**
4666             * Gets the list of instruments in the specified directory.
4667             * @param dir The absolute path name of the directory.
4668             * @return A <code>DbInstrumentInfo</code> array providing
4669             * information about all instruments in the specified directory.
4670             * @throws IOException If some I/O error occurs.
4671             * @throws LscpException If LSCP protocol corruption occurs.
4672             * @throws LSException If the specified path name is invalid.
4673             */
4674            public synchronized DbInstrumentInfo[]
4675            getDbInstruments(String dir) throws IOException, LscpException, LSException {
4676                    String[] instrS = getDbInstrumentNames(dir);
4677                    if(!hasEndingFileSeparator(dir)) dir += "/";
4678                    
4679                    DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length];
4680                    for(int i = 0; i < instrS.length; i++) {
4681                            infoS[i] = getDbInstrumentInfo(conv(dir) + toEscapedFsEntry(instrS[i]));
4682                    }
4683                    return infoS;
4684            }
4685            
4686            /**
4687             * Gets the list of instruments in the specified directory.
4688             * @param dir The absolute path name of the directory.
4689             * @return A <code>DbInstrumentInfo</code> array providing
4690             * information about all instruments in the specified directory.
4691             * @throws IOException If some I/O error occurs.
4692             * @throws LscpException If LSCP protocol corruption occurs.
4693             * @throws LSException If the specified path name is invalid.
4694             *
4695            public synchronized DbInstrumentInfo[]
4696            getDbInstruments(String dir) throws IOException, LscpException, LSException {
4697                    String[] instrS = getDbInstrumentNames(dir);
4698                    if(instrS.length == 0) return new DbInstrumentInfo[0];
4699                    
4700                    if(dir.charAt(dir.length() - 1) != '/') dir += "/"; FIXME:
4701                    
4702                    for(int i = 0; i < instrS.length; i++) {
4703                            out.writeLine("GET DB_INSTRUMENT INFO '" + conv(dir) + instrS[i] + "'");
4704                    }
4705                    
4706                    if(getPrintOnlyMode()) return null;
4707                    
4708                    if(dir.length() > 1) dir = dir.substring(0, dir.length() - 1);
4709                    StringBuffer sb = new StringBuffer();
4710                    DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length];
4711                    for(int i = 0; i < instrS.length; i++) {
4712                            try {
4713                                    ResultSet rs = getMultiLineResultSet();
4714                                    infoS[i] = new DbInstrumentInfo(rs.getMultiLineResult());
4715                                    infoS[i].setName(instrS[i]);
4716                                    infoS[i].setDirectoryPath(dir);
4717                            } catch (SocketTimeoutException e) {
4718                                    getLogger().log(Level.FINE, e.getMessage(), e);
4719                                    sb.append(e.getMessage()).append("\n");
4720                                    break;
4721                            } catch (Exception e) {
4722                                    getLogger().log(Level.FINE, e.getMessage(), e);
4723                                    sb.append(e.getMessage()).append("\n");
4724                            }
4725                    }
4726                    
4727                    String details = sb.toString();
4728                    if(details.length() > 0) {
4729                            String err = LscpI18n.getLogMsg("Client.getInstrsInfoFailed!");
4730                            throw new LSException(0, err, details);
4731                    }
4732                    
4733                    return infoS;
4734            }*/
4735            
4736            /**
4737             * Renames the specified instrument.
4738             * @param instr The absolute path name of the instrument to rename.
4739             * @param name The new name for the instrument.
4740             * @throws IOException If some I/O error occurs.
4741             * @throws LSException If the renaming of the instrument failed.
4742             * @throws LscpException If LSCP protocol corruption occurs.
4743             */
4744            public synchronized void
4745            renameDbInstrument(String instr, String name)
4746                                    throws IOException, LSException, LscpException {
4747                    
4748                    verifyConnection();
4749                    name = toEscapedText(name);
4750                    out.writeLine("SET DB_INSTRUMENT NAME '" + conv(instr) + "' '" + conv(name) + "'");
4751                    if(getPrintOnlyMode()) return;
4752                    
4753                    ResultSet rs = getEmptyResultSet();
4754            }
4755            
4756            /**
4757             * Moves the specified instrument into the specified location.
4758             * @param instr The absolute path name of the instrument to move.
4759             * @param dst The directory where the specified instrument will be moved to.
4760             * @throws IOException If some I/O error occurs.
4761             * @throws LSException If the operation failed.
4762             * @throws LscpException If LSCP protocol corruption occurs.
4763             */
4764            public synchronized void
4765            moveDbInstrument(String instr, String dst) throws IOException, LSException, LscpException {
4766                    verifyConnection();
4767                    out.writeLine("MOVE DB_INSTRUMENT '" + conv(instr) + "' '" + conv(dst) + "'");
4768                    if(getPrintOnlyMode()) return;
4769                    
4770                    ResultSet rs = getEmptyResultSet();
4771            }
4772            
4773            /**
4774             * Moves the specified instruments into the specified location.
4775             * @param instrs The absolute path names of the instruments to move.
4776             * @param dst The directory where the specified instruments will be moved to.
4777             * @throws IOException If some I/O error occurs.
4778             * @throws LSException If the operation failed.
4779             * @throws LscpException If LSCP protocol corruption occurs.
4780             */
4781            public synchronized void
4782            moveDbInstruments(String[] instrs, String dst) throws IOException, LSException, LscpException {
4783                    verifyConnection();
4784                    for(String s : instrs) {
4785                            out.writeLine("MOVE DB_INSTRUMENT '" + conv(s) + "' '" + conv(dst) + "'");
4786                    }
4787                    if(getPrintOnlyMode()) return;
4788                    
4789                    getEmptyResultSets(instrs.length, "Client.instrMovingFailed!");
4790            }
4791            
4792            /**
4793             * Copies the specified instrument into the specified location.
4794             * @param instr The absolute path name of the instrument to copy.
4795             * @param dst The directory where the specified instrument will be copied to.
4796             * @throws IOException If some I/O error occurs.
4797             * @throws LSException If the operation failed.
4798             * @throws LscpException If LSCP protocol corruption occurs.
4799             */
4800            public synchronized void
4801            copyDbInstrument(String instr, String dst) throws IOException, LSException, LscpException {
4802                    verifyConnection();
4803                    out.writeLine("COPY DB_INSTRUMENT '" + conv(instr) + "' '" + conv(dst) + "'");
4804                    if(getPrintOnlyMode()) return;
4805                    
4806                    ResultSet rs = getEmptyResultSet();
4807            }
4808            
4809            /**
4810             * Copies the specified instruments into the specified location.
4811             * @param instrs The absolute path name of the instruments to copy.
4812             * @param dst The directory where the specified instruments will be copied to.
4813             * @throws IOException If some I/O error occurs.
4814             * @throws LSException If the operation failed.
4815             * @throws LscpException If LSCP protocol corruption occurs.
4816             */
4817            public synchronized void
4818            copyDbInstruments(String[] instrs, String dst) throws IOException, LSException, LscpException {
4819                    verifyConnection();
4820                    for(String s : instrs) {
4821                            out.writeLine("COPY DB_INSTRUMENT '" + conv(s) + "' '" + conv(dst) + "'");
4822                    }
4823                    if(getPrintOnlyMode()) return;
4824                    
4825                    getEmptyResultSets(instrs.length, "Client.instrCopyingFailed!");
4826            }
4827            
4828            /**
4829             * Changes the description of the specified instrument.
4830             * @param instr The absolute path name of the instrument.
4831             * @param desc The new description for the instrument.
4832             * @throws IOException If some I/O error occurs.
4833             * @throws LSException If failed to change the description.
4834             * @throws LscpException If LSCP protocol corruption occurs.
4835             */
4836            public synchronized void
4837            setDbInstrumentDescription(String instr, String desc)
4838                                    throws IOException, LSException, LscpException {
4839                    
4840                    verifyConnection();
4841                    desc = toEscapedText(desc);
4842                    out.writeLine("SET DB_INSTRUMENT DESCRIPTION '" + conv(instr) + "' '" + desc + "'");
4843                    if(getPrintOnlyMode()) return;
4844                    
4845                    ResultSet rs = getEmptyResultSet();
4846            }
4847            
4848            /**
4849             * Substitutes all occurrences of the instrument file
4850             * <code>oldPath</code> in the database, with <code>newPath</code>.
4851             * @param oldPath The absolute path name of the instrument file to substitute.
4852             * @param newPath The new absolute path name.
4853             * @throws IOException If some I/O error occurs.
4854             * @throws LSException If the operation failed.
4855             * @throws LscpException If LSCP protocol corruption occurs.
4856             */
4857            public synchronized void
4858            setDbInstrumentFilePath(String oldPath, String newPath)
4859                                    throws IOException, LSException, LscpException {
4860                    
4861                    verifyConnection();
4862                    out.writeLine("SET DB_INSTRUMENT FILE_PATH '" + conv(oldPath) + "' '" + conv(newPath) + "'");
4863                    if(getPrintOnlyMode()) return;
4864                    
4865                    ResultSet rs = getEmptyResultSet();
4866            }
4867            
4868            /**
4869             * Finds all directories in the specified directory
4870             * that corresponds to the specified search criterias.
4871             * @param dir The absolute path name of the directory to search.
4872             * @param query Provides the search criterias.
4873             * @return A <code>DbDirectoryInfo</code> array providing
4874             * information about all directories that are found in the specified directory.
4875             * @throws IOException If some I/O error occurs.
4876             * @throws LscpException If LSCP protocol corruption occurs.
4877             * @throws LSException If the specified path name is invalid.
4878             */
4879            public synchronized DbDirectoryInfo[]
4880            findDbDirectories(String dir, DbSearchQuery query)
4881                                    throws IOException, LscpException, LSException {
4882                    
4883                    return findDbDirectories(dir, query, false);
4884            }
4885            
4886            /**
4887             * Finds all directories in the specified directory
4888             * that corresponds to the specified search criterias.
4889             * @param dir The absolute path name of the directory to search.
4890             * @param query Provides the search criterias.
4891             * @param nonRecursive If <code>true</code>, the search will be non-recursive.
4892             * @return A <code>DbDirectoryInfo</code> array providing
4893             * information about all directories that are found in the specified directory.
4894             * @throws IOException If some I/O error occurs.
4895             * @throws LscpException If LSCP protocol corruption occurs.
4896             * @throws LSException If the specified path name is invalid.
4897             */
4898            public synchronized DbDirectoryInfo[]
4899            findDbDirectories(String dir, DbSearchQuery query, boolean nonRecursive)
4900                                    throws IOException, LscpException, LSException {
4901                    
4902                    verifyConnection();
4903                    StringBuffer sb = new StringBuffer();
4904                    sb.append("FIND DB_INSTRUMENT_DIRECTORIES");
4905                    if(nonRecursive) sb.append(" NON_RECURSIVE");
4906                    sb.append(" '").append(conv(dir)).append("'");
4907                    
4908                    if(query.name != null && query.name.length() > 0) {
4909                            sb.append(" NAME='").append(toEscapedText(query.name)).append("'");
4910                    }
4911                    
4912                    String s = query.getCreatedAfter();
4913                    String s2 = query.getCreatedBefore();
4914                    if(s != null || s2 != null) {
4915                            sb.append(" CREATED='");
4916                            if(s != null) sb.append(s);
4917                            sb.append("..");
4918                            if(s2 != null) sb.append(s2);
4919                            sb.append("'");
4920                    }
4921                    
4922                    s = query.getModifiedAfter();
4923                    s2 = query.getModifiedBefore();
4924                    if(s != null || s2 != null) {
4925                            sb.append(" MODIFIED='");
4926                            if(s != null) sb.append(s);
4927                            sb.append("..");
4928                            if(s2 != null) sb.append(s2);
4929                            sb.append("'");
4930                    }
4931                    
4932                    if(query.description != null && query.description.length() > 0) {
4933                            sb.append(" DESCRIPTION='");
4934                            sb.append(toEscapedText(query.description)).append("'");
4935                    }
4936                    
4937                    out.writeLine(sb.toString());
4938                    if(getPrintOnlyMode()) return null;
4939                    
4940                    String[] dirS = parseEscapedStringList(getSingleLineResultSet().getResult());
4941                    
4942                    DbDirectoryInfo[] infoS = new DbDirectoryInfo[dirS.length];
4943                    for(int i = 0; i < dirS.length; i++) {
4944                            infoS[i] = getDbDirectoryInfo(dirS[i]);
4945                    }
4946                    return infoS;
4947            }
4948            
4949            /**
4950             * Finds all instruments in the specified directory
4951             * that corresponds to the specified search criterias.
4952             * @param dir The absolute path name of the directory to search.
4953             * @param query Provides the search criterias.
4954             * @return A <code>DbInstrumentInfo</code> array providing
4955             * information about all instruments that are found in the specified directory.
4956             * @throws IOException If some I/O error occurs.
4957             * @throws LscpException If LSCP protocol corruption occurs.
4958             * @throws LSException If the specified path name is invalid.
4959             */
4960            public synchronized DbInstrumentInfo[]
4961            findDbInstruments(String dir, DbSearchQuery query)
4962                                    throws IOException, LscpException, LSException {
4963                    
4964                    return findDbInstruments(dir, query, false);
4965            }
4966            
4967            /**
4968             * Finds all instruments in the specified directory
4969             * that corresponds to the specified search criterias.
4970             * @param dir The absolute path name of the directory to search.
4971             * @param query Provides the search criterias.
4972             * @param nonRecursive If <code>true</code>, the search will be non-recursive.
4973             * @return A <code>DbInstrumentInfo</code> array providing
4974             * information about all instruments that are found in the specified directory.
4975             * @throws IOException If some I/O error occurs.
4976             * @throws LscpException If LSCP protocol corruption occurs.
4977             * @throws LSException If the specified path name is invalid.
4978             */
4979            public synchronized DbInstrumentInfo[]
4980            findDbInstruments(String dir, DbSearchQuery query, boolean nonRecursive)
4981                                    throws IOException, LscpException, LSException {
4982                    
4983                    verifyConnection();
4984                    StringBuffer sb = new StringBuffer();
4985                    sb.append("FIND DB_INSTRUMENTS");
4986                    if(nonRecursive) sb.append(" NON_RECURSIVE");
4987                    sb.append(" '").append(conv(dir)).append("'");
4988                    
4989                    if(query.name != null && query.name.length() > 0) {
4990                            sb.append(" NAME='").append(toEscapedText(query.name)).append("'");
4991                    }
4992                    
4993                    if(query.formatFamilies.size() > 0) {
4994                            sb.append(" FORMAT_FAMILIES='").append(query.formatFamilies.get(0));
4995                            for(int i = 1; i < query.formatFamilies.size(); i++) {
4996                                    sb.append(',').append(query.formatFamilies.get(i));
4997                            }
4998                            sb.append("'");
4999                    }
5000                    
5001                    if(query.minSize != -1 || query.maxSize != -1) {
5002                            sb.append(" SIZE='");
5003                            if(query.minSize != -1) sb.append(query.minSize);
5004                            sb.append("..");
5005                            if(query.maxSize != -1) sb.append(query.maxSize);
5006                            sb.append("'");
5007                    }
5008                    
5009                    String s = query.getCreatedAfter();
5010                    String s2 = query.getCreatedBefore();
5011                    if(s != null || s2 != null) {
5012                            sb.append(" CREATED='");
5013                            if(s != null) sb.append(s);
5014                            sb.append("..");
5015                            if(s2 != null) sb.append(s2);
5016                            sb.append("'");
5017                    }
5018                    
5019                    s = query.getModifiedAfter();
5020                    s2 = query.getModifiedBefore();
5021                    if(s != null || s2 != null) {
5022                            sb.append(" MODIFIED='");
5023                            if(s != null) sb.append(s);
5024                            sb.append("..");
5025                            if(s2 != null) sb.append(s2);
5026                            sb.append("'");
5027                    }
5028                    
5029                    if(query.description != null && query.description.length() > 0) {
5030                            sb.append(" DESCRIPTION='");
5031                            sb.append(toEscapedText(query.description)).append("'");
5032                    }
5033                    
5034                    if(query.instrumentType != DbSearchQuery.InstrumentType.BOTH) {
5035                            sb.append(" IS_DRUM=");
5036                            if(query.instrumentType == DbSearchQuery.InstrumentType.DRUM) {
5037                                    sb.append("'true'");
5038                            } else {
5039                                    sb.append("'false'");
5040                            }
5041                    }
5042                    
5043                    if(query.product != null && query.product.length() > 0) {
5044                            sb.append(" PRODUCT='").append(toEscapedText(query.product)).append("'");
5045                    }
5046                    
5047                    if(query.artists != null && query.artists.length() > 0) {
5048                            sb.append(" ARTISTS='").append(toEscapedText(query.artists)).append("'");
5049                    }
5050                    
5051                    if(query.keywords != null && query.keywords.length() > 0) {
5052                            sb.append(" KEYWORDS='");
5053                            sb.append(toEscapedText(query.keywords)).append("'");
5054                    }
5055                    
5056                    out.writeLine(sb.toString());
5057                    if(getPrintOnlyMode()) return null;
5058                    
5059                    String[] instrS = parseEscapedStringList(getSingleLineResultSet().getResult());
5060                    
5061                    DbInstrumentInfo[] infoS = new DbInstrumentInfo[instrS.length];
5062                    for(int i = 0; i < instrS.length; i++) {
5063                            infoS[i] = getDbInstrumentInfo(instrS[i]);
5064                    }
5065                    return infoS;
5066            }
5067            
5068            /**
5069             * Returns a list of all instrument files in the database
5070             * that that don't exist in the filesystem.
5071             * @throws IOException If some I/O error occurs.
5072             * @throws LscpException If LSCP protocol corruption occurs.
5073             * @throws LSException If other error occurs.
5074             */
5075            public synchronized String[]
5076            findLostDbInstrumentFiles() throws IOException, LscpException, LSException {
5077                    
5078                    verifyConnection();
5079                    out.writeLine("FIND LOST DB_INSTRUMENT_FILES");
5080                    if(getPrintOnlyMode()) return null;
5081                    
5082                    return parseEscapedStringList(getSingleLineResultSet().getResult());
5083            }
5084            
5085            /**
5086             * Gets status information about the specified job.
5087             * @param jobId The ID of the job.
5088             * @return A <code>ScanJobInfo</code> instance providing information
5089             * about the specified job.
5090             * @throws IOException If some I/O error occurs.
5091             * @throws LscpException If LSCP protocol corruption occurs.
5092             * @throws LSException If the specified job is not found.
5093             */
5094            public synchronized ScanJobInfo
5095            getDbInstrumentsJobInfo(int jobId) throws IOException, LscpException, LSException {
5096                    verifyConnection();
5097                    out.writeLine("GET DB_INSTRUMENTS_JOB INFO " + String.valueOf(jobId));
5098                    if(getPrintOnlyMode()) return null;
5099                    
5100                    ResultSet rs = getMultiLineResultSet();
5101                    ScanJobInfo info = new ScanJobInfo(rs.getMultiLineResult());
5102                    
5103                    return info;
5104            }
5105            
5106            /**
5107             * Removes all instruments and directories and re-creates
5108             * the instruments database structure.
5109             * @throws IOException If some I/O error occurs.
5110             * @throws LscpException If LSCP protocol corruption occurs.
5111             * @throws LSException If the formatting of the instruments database failed.
5112             */
5113            public synchronized void
5114            formatInstrumentsDb() throws IOException, LscpException, LSException {
5115                    verifyConnection();
5116                    out.writeLine("FORMAT INSTRUMENTS_DB");
5117                    if(getPrintOnlyMode()) return;
5118                    
5119                    ResultSet rs = getEmptyResultSet();
5120            }
5121            
5122            /**
5123           * Resets the specified sampler channel.           * Resets the specified sampler channel.
5124           *           *
5125           * @param samplerChn The sampler channel number.           * @param samplerChn The sampler channel number.
# Line 3604  public class Client { Line 5156  public class Client {
5156          }          }
5157                    
5158          /**          /**
5159             * Gets the current number of all active streams.
5160             * @return The current number of all active streams.
5161             * @throws IOException If some I/O error occurs.
5162             * @throws LscpException If LSCP protocol corruption occurs.
5163             * @throws LSException If some other error occurs.
5164             */
5165            public synchronized int
5166            getTotalStreamCount() throws IOException, LscpException, LSException {
5167                    verifyConnection();
5168                    out.writeLine("GET TOTAL_STREAM_COUNT");
5169                    if(getPrintOnlyMode()) return -1;
5170                    
5171                    String s = getSingleLineResultSet().getResult();
5172                    return parseInt(s);
5173            }
5174            
5175            /**
5176           * Gets the current number of all active voices.           * Gets the current number of all active voices.
5177           * @return The current number of all active voices.           * @return The current number of all active voices.
5178           * @throws IOException If some I/O error occurs.           * @throws IOException If some I/O error occurs.
# Line 3693  public class Client { Line 5262  public class Client {
5262          }          }
5263                    
5264          /**          /**
5265             * Gets the number of instruments in the specified instrument file.
5266             * @param filename The absolute path name of the instrument file.
5267             * @return The number of instruments in the specified instrument file.
5268             * @throws IOException If some I/O error occurs.
5269             * @throws LscpException If LSCP protocol corruption occurs.
5270             * @throws LSException If the file is not found, or other error occur.
5271             */
5272            public synchronized int
5273            getFileInstrumentCount(String filename) throws IOException, LscpException, LSException {
5274                    verifyConnection();
5275                    out.writeLine("GET FILE INSTRUMENTS '" + conv(filename) +"'");
5276                    if(getPrintOnlyMode()) return -1;
5277                    
5278                    String s = getSingleLineResultSet().getResult();
5279                    return parseInt(s);
5280            }
5281            
5282            /**
5283             * Gets information about the instrument with index
5284             * <code>instrIdx</code> in the specified instrument file.
5285             * @param filename The absolute path name of the instrument file.
5286             * @param instrIdx The index of the instrument in the specified instrument file.
5287             * @throws IOException If some I/O error occurs.
5288             * @throws LscpException If LSCP protocol corruption occurs.
5289             * @throws LSException If failed to retrieve information.
5290             */
5291            public synchronized Instrument
5292            getFileInstrumentInfo(String filename, int instrIdx)
5293                                    throws IOException, LscpException, LSException {
5294                    
5295                    verifyConnection();
5296                    out.writeLine("GET FILE INSTRUMENT INFO '" + conv(filename) + "' " + String.valueOf(instrIdx));
5297                    if(getPrintOnlyMode()) return null;
5298                    
5299                    ResultSet rs = getMultiLineResultSet();
5300                    Instrument instr = new FileInstrument(rs.getMultiLineResult()) { };
5301                    
5302                    return instr;
5303            }
5304            
5305            /**
5306             * Gets the list of instruments in the specified instrument file.
5307             * @param filename The absolute path name of the instrument file.
5308             * @return An <code>Instrument</code> array providing
5309             * information about all instruments in the specified instrument file.
5310             * @throws IOException If some I/O error occurs.
5311             * @throws LscpException If LSCP protocol corruption occurs.
5312             * @throws LSException If the specified file name is invalid.
5313             */
5314            public synchronized Instrument[]
5315            getFileInstruments(String filename) throws IOException, LscpException, LSException {
5316                    int l = getFileInstrumentCount(filename);
5317                    if(l < 0) return null;
5318                    Instrument[] instrS = new FileInstrument[l];
5319                    
5320                    for(int i = 0; i < instrS.length; i++) {
5321                            instrS[i] = getFileInstrumentInfo(filename, i);
5322                    }
5323                    return instrS;
5324            }
5325            
5326            private static class FileInstrument extends AbstractInstrument {
5327                    FileInstrument(String[] resultSet) throws LscpException {
5328                            super(resultSet);
5329                    }
5330                    
5331                    public String
5332                    getEngine() {
5333                            // TODO: engine lookup?
5334                            return getFormatFamily();
5335                    }
5336                    
5337                    public boolean
5338                    parse(String s) throws LscpException {
5339                            if(s.startsWith("PRODUCT: ") || s.startsWith("ARTISTS: ")) return true;
5340                            return super.parse(s);
5341                    }
5342            }
5343            
5344            private void
5345            getEmptyResultSets(int count, String err) throws LSException {
5346                    StringBuffer sb = new StringBuffer();
5347                    for(int i = 0; i < count; i++) {
5348                            try { getEmptyResultSet(); }
5349                            catch (SocketTimeoutException e) {
5350                                    getLogger().log(Level.FINE, e.getMessage(), e);
5351                                    sb.append(e.getMessage()).append("\n");
5352                                    break;
5353                            } catch (Exception e) {
5354                                    getLogger().log(Level.FINE, e.getMessage(), e);
5355                                    sb.append(e.getMessage()).append("\n");
5356                            }
5357                    }
5358                    
5359                    String details = sb.toString();
5360                    if(details.length() > 0) {
5361                            String s = LscpI18n.getLogMsg(err);
5362                            throw new LSException(0, s, details);
5363                    }
5364            }
5365            
5366            /**
5367           * Returns the logger for this library.           * Returns the logger for this library.
5368           * @return The logger for this library.           * @return The logger for this library.
5369           */           */

Legend:
Removed from v.1139  
changed lines
  Added in v.1766

  ViewVC Help
Powered by ViewVC