Source Code Cross Referenced for SDPClient.java in  » 6.0-JDK-Modules » j2me » com » sun » kvem » jsr082 » bluetooth » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » com.sun.kvem.jsr082.bluetooth 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *
003:         *
004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006:         * 
007:         * This program is free software; you can redistribute it and/or
008:         * modify it under the terms of the GNU General Public License version
009:         * 2 only, as published by the Free Software Foundation.
010:         * 
011:         * This program is distributed in the hope that it will be useful, but
012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014:         * General Public License version 2 for more details (a copy is
015:         * included at /legal/license.txt).
016:         * 
017:         * You should have received a copy of the GNU General Public License
018:         * version 2 along with this work; if not, write to the Free Software
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020:         * 02110-1301 USA
021:         * 
022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023:         * Clara, CA 95054 or visit www.sun.com if you need additional
024:         * information or have any questions.
025:         */
026:        package com.sun.kvem.jsr082.bluetooth;
027:
028:        import javax.bluetooth.DataElement;
029:        import javax.bluetooth.L2CAPConnection;
030:        import javax.bluetooth.UUID;
031:        import java.util.Enumeration;
032:        import java.util.Hashtable;
033:        import java.io.IOException;
034:
035:        /**
036:         * SDPClient class provides a client side of SDP connection as described in
037:         * Bluetooth Specification version 1.2.
038:         */
039:        class SDPClient {
040:
041:            /** Max retrievable service record handles. Maybe defined via property. */
042:            private static final int MAX_SERVICE_RECORD_COUNT = 0x0fff;
043:
044:            /** Max total size of retrievable attributes. Maybe defined via property. */
045:            private static final int MAX_ATTRIBUTE_BYTE_COUNT = 0xffff;
046:
047:            /**
048:             * The lowest possible value of transaction ID.
049:             * The number must be positive.
050:             */
051:            private static final int firstTransactionID = 0x0001;
052:
053:            /** The maximum possible value of transaction ID. */
054:            private static final int maxTransactionID = 0xffff;
055:
056:            /** Next transaction ID. */
057:            private static int effectiveTransactionID = firstTransactionID;
058:
059:            /** Maps Bluetooth addresses to transport connections. */
060:            private static Hashtable transportStorage = new Hashtable();
061:
062:            /** Transport connection for this client. */
063:            private SDPTransport transport;
064:
065:            /** Bluetooth address this client is connected to. */
066:            private String address = null;
067:
068:            /**
069:             * Constructs an <code>SDPClient<code> object and opens SDP connection
070:             * to the remote device with the specified Bluetooth address.
071:             *
072:             * @param bluetoothAddress bluetooth address of SDP server
073:             */
074:            SDPClient(String bluetoothAddress) throws IOException {
075:                address = bluetoothAddress;
076:                synchronized (transportStorage) {
077:                    transport = (SDPTransport) transportStorage.get(address);
078:                    if (transport == null) {
079:                        transport = new SDPTransport(address);
080:                        transportStorage.put(address, transport);
081:                    }
082:                }
083:                transport.addRef();
084:            }
085:
086:            /**
087:             * Retrieves next new transaction ID.
088:             *
089:             * @return new transaction ID.
090:             */
091:            static synchronized short newTransactionID() {
092:                int transactionID = effectiveTransactionID++;
093:                if (effectiveTransactionID > maxTransactionID) {
094:                    // strictly speaking, this is not quite safe,
095:                    // need revisit : if we have a pending
096:                    // transaction after 64K of subsequent calls
097:                    effectiveTransactionID = firstTransactionID;
098:                }
099:                return (short) transactionID;
100:            }
101:
102:            /**
103:             * Frees transaction ID.
104:             *
105:             * @param transactionID the ID to free.
106:             */
107:            static synchronized void freeTransactionID(short transactionID) {
108:                // empty in this implementation
109:            }
110:
111:            /**
112:             * Closes connection of this client to the specified server.
113:             *
114:             * @throws IOException if no connection is open
115:             */
116:            void close() throws IOException {
117:                if (transport == null) {
118:                    throw new IOException("Connection is already closed.");
119:                }
120:                transport.release();
121:                transport = null;
122:            }
123:
124:            /**
125:             * Initiates ServiceSearch transaction that is used to search for
126:             * services that have all the UUIDs specified on a server.
127:             */
128:            void serviceSearchRequest(UUID[] uuidSet, int transactionID,
129:                    SDPResponseListener listener) throws IOException {
130:                try {
131:                    transport.serviceSearchRequest(uuidSet, transactionID,
132:                            listener);
133:                } catch (IOException ioe) {
134:                    transport.cancelAll(SDPResponseListener.IO_ERROR);
135:                    throw ioe;
136:                }
137:            }
138:
139:            /**
140:             * Initiates ServiceAttribute transaction that retrieves
141:             * specified attribute values from a specific service record.
142:             */
143:            void serviceAttributeRequest(int serviceRecordHandle,
144:                    int[] attrSet, int transactionID,
145:                    SDPResponseListener listener) throws IOException {
146:                try {
147:                    transport.serviceAttributeRequest(serviceRecordHandle,
148:                            attrSet, transactionID, listener);
149:                } catch (IOException e) {
150:                    transport.cancelAll(SDPResponseListener.IO_ERROR);
151:                    throw e;
152:                }
153:            }
154:
155:            /**
156:             * Initiates ServiceSearchAttribute transaction that searches for services
157:             * on a server by UUIDs specified and retrieves values of specified
158:             * parameters for service records found.
159:             */
160:            void serviceSearchAttributeRequest(int[] attrSet, UUID[] uuidSet,
161:                    int transactionID, SDPResponseListener listener)
162:                    throws IOException {
163:                try {
164:                    transport.serviceSearchAttributeRequest(attrSet, uuidSet,
165:                            transactionID, listener);
166:                } catch (IOException e) {
167:                    transport.cancelAll(SDPResponseListener.IO_ERROR);
168:                    throw e;
169:                }
170:            }
171:
172:            /**
173:             * Cancels transaction with given ID.
174:             */
175:            boolean cancelServiceSearch(int transactionID) {
176:                return transport.cancelServiceSearch(transactionID);
177:            }
178:
179:            /**
180:             * SDP transport connection.
181:             */
182:            private static class SDPTransport {
183:
184:                /** Bluetooth address of the server. */
185:                private String address;
186:
187:                /**
188:                 * Reference counter keeps the number of SDP connections which
189:                 * use this transport. When this value reaches zero, the L2CAP
190:                 * connection is closed and the transport is removed from the global
191:                 * SDPClient.transportStorage hashtable.
192:                 */
193:                private int refCount = 0;
194:
195:                /** The L2CAP (logical link) connection. */
196:                private L2CAPConnection connection;
197:
198:                /**
199:                 * Object that performs reading from and writing to L2CAP connection.
200:                 */
201:                private DataL2CAPReaderWriter rw;
202:
203:                /** Maps transaction IDs to ServiceTransaction objects. */
204:                private Hashtable transactions = new Hashtable();
205:
206:                /** Response receiver. */
207:                private Receiver receiver = new Receiver();
208:
209:                /** Lock for synchronizing reading from connection. */
210:                private Object readLock = new Object();
211:
212:                /** Lock for synchronizing writing to connection. */
213:                private Object writeLock = new Object();
214:
215:                /**
216:                 * Helper object which serializes and restores
217:                 * <code>DataElement</code>s.
218:                 */
219:                private static DataElementSerializer des = new DataElementSerializer();
220:
221:                /** ID of SDP_ErrorResponse protocol data unit. */
222:                private static final int SDP_ERROR_RESPONSE = 0x01;
223:
224:                /** ID of SDP_ServiceSearchRequest protocol data unit. */
225:                private static final int SDP_SERVICE_SEARCH_REQUEST = 0x02;
226:
227:                /** ID of SDP_ServiceSearchResponse protocol data unit. */
228:                private static final int SDP_SERVICE_SEARCH_RESPONSE = 0x03;
229:
230:                /** ID of SDP_ServiceAttributeRequest protocol data unit. */
231:                private static final int SDP_SERVICE_ATTRIBUTE_REQUEST = 0x04;
232:
233:                /** ID of SDP_ServiceAttributeResponse protocol data unit. */
234:                private static final int SDP_SERVICE_ATTRIBUTE_RESPONSE = 0x05;
235:
236:                /** ID of SDP_ServiceSearchAttributeRequest protocol data unit. */
237:                private static final int SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST = 0x06;
238:
239:                /** ID of SDP_ServiceSearchAttributeResponse protocol data unit. */
240:                private static final int SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE = 0x07;
241:
242:                /** L2CAP URL starting string. */
243:                private static final String SDP_L2CAP_URL_BEGIN = "//";
244:
245:                /** L2CAP URL trailing string. */
246:                private static final String SDP_L2CAP_URL_END = ":0001";
247:
248:                /**
249:                 * Constricts <code>SDPTransport</code> instance that reflects transport
250:                 * connections to the specified server.
251:                 *
252:                 * @param bluetoothAddress bluetooth address of the server
253:                 */
254:                private SDPTransport(String bluetoothAddress)
255:                        throws IOException {
256:                    address = bluetoothAddress;
257:                    connection = (L2CAPConnection) SDP
258:                            .getL2CAPConnection(SDP_L2CAP_URL_BEGIN
259:                                    + bluetoothAddress + SDP_L2CAP_URL_END);
260:                    rw = new DataL2CAPReaderWriter(connection);
261:                }
262:
263:                /**
264:                 * Increases reference counter. This object and the underlying L2CAP
265:                 * connection will live while the counter is positive.
266:                 */
267:                private synchronized void addRef() {
268:                    refCount++;
269:                }
270:
271:                /**
272:                 * Decreases reference counter. If the counter becomes equal to zero,
273:                 * L2CAP connection is closed and the transport is removed from the
274:                 * global SDPClient.transportStorage hashtable.
275:                 */
276:                private synchronized void release() {
277:                    refCount--;
278:                    if (refCount == 0) {
279:                        try {
280:                            connection.close();
281:                        } catch (IOException e) {
282:                            // just ignore it, we're done with this object anyway
283:                        }
284:                        receiver.cancel();
285:                        synchronized (transportStorage) {
286:                            transportStorage.remove(address);
287:                        }
288:                    }
289:                }
290:
291:                /**
292:                 * Cancels a transaction with specified ID.
293:                 */
294:                boolean cancelTransaction(int transactionID, int reason) {
295:                    // key for transactions hastable is effectiveTransactionID not
296:                    // transactionID so we need to iterate over the hashatble looking
297:                    // for the transactionID
298:                    Enumeration e = transactions.elements();
299:                    while (e.hasMoreElements()) {
300:                        ServiceTransaction trans = (ServiceTransaction) e
301:                                .nextElement();
302:                        if (trans != null
303:                                && trans.transactionID == transactionID) {
304:                            transactions.remove(new Integer(
305:                                    trans.effectiveTransactionID));
306:                            // the transaction is removed from transactions hashtable by
307:                            // ServiceTransaction.end() called from
308:                            // ServiceTransaction.cancel(). The cancel()  reports to the
309:                            // listener what transaction is terminated.
310:                            trans.cancel(reason);
311:                            return true;
312:                        }
313:                    }
314:                    return false;
315:                }
316:
317:                /**
318:                 * Cancels all current transactions. Called in case of I/O failure
319:                 * in the underlying L2CAP connection.
320:                 */
321:                synchronized void cancelAll(int reason) {
322:                    // force actual release of resources
323:                    refCount = 1;
324:                    release();
325:                    Enumeration e = transactions.elements();
326:                    while (e.hasMoreElements()) {
327:                        ServiceTransaction trans = (ServiceTransaction) e
328:                                .nextElement();
329:                        trans.listener.errorResponse(reason, "",
330:                                trans.transactionID);
331:                    }
332:                    transactions.clear();
333:                }
334:
335:                /**
336:                 * Starts ServiceSearch transaction.
337:                 */
338:                void serviceSearchRequest(UUID[] uuidSet, int transactionID,
339:                        SDPResponseListener listener) throws IOException {
340:                    new ServiceSearchTransaction(transactionID, listener,
341:                            uuidSet).start();
342:                }
343:
344:                /**
345:                 * Starts ServiceAttribute transaction.
346:                 */
347:                void serviceAttributeRequest(int serviceRecordHandle,
348:                        int[] attrSet, int transactionID,
349:                        SDPResponseListener listener) throws IOException {
350:                    new ServiceAttributeTransaction(transactionID, listener,
351:                            serviceRecordHandle, attrSet).start();
352:                }
353:
354:                /**
355:                 * Starts ServiceSearchAttribute transaction.
356:                 */
357:                void serviceSearchAttributeRequest(int[] attrSet,
358:                        UUID[] uuidSet, int transactionID,
359:                        SDPResponseListener listener) throws IOException {
360:                    new ServiceSearchAttributeTransaction(transactionID,
361:                            listener, attrSet, uuidSet).start();
362:                }
363:
364:                /**
365:                 * Cancels a transaction with specified ID with reason
366:                 * <code>SDPResponseListener.TERMINATED</code>.
367:                 */
368:                boolean cancelServiceSearch(int transactionID) {
369:                    return cancelTransaction(transactionID,
370:                            SDPResponseListener.TERMINATED);
371:                }
372:
373:                /**
374:                 * Gets next SDP server response, if any, and passes it to the
375:                 * corresponding listener. If a response is received, the transaction
376:                 * it belongs to is stopped.
377:                 *
378:                 * @throws IOException if an I/O error occurs
379:                 */
380:                void processResponse() throws IOException {
381:                    ServiceTransaction trans;
382:                    synchronized (readLock) {
383:                        byte pduID = rw.readByte();
384:                        short transID = rw.readShort();
385:                        short length = rw.readShort();
386:                        // System.out.println("received pdu " + pduID +
387:                        //         " trans " + transID);
388:
389:                        trans = (ServiceTransaction) transactions
390:                                .get(new Integer(transID));
391:
392:                        if (trans == null) {
393:                            // System.out.println("not found");
394:                            // transaction we are not aware of; skip this pdu
395:                            rw.readBytes(length);
396:                            return;
397:                        }
398:                        if (pduID == SDP_ERROR_RESPONSE) {
399:                            trans.error(length);
400:                            return;
401:                        }
402:                        trans.readParameters(length);
403:                    }
404:                    trans.process();
405:                }
406:
407:                /**
408:                 * SDP response receiver.
409:                 */
410:                private class Receiver implements  Runnable {
411:                    /** A counter to identify if the receiver has clients. */
412:                    private int startCounter = 0;
413:
414:                    /** Identifies if receiving is cancelled. */
415:                    private boolean canceled = false;
416:
417:                    /**
418:                     * Identifies if receiving thread is running (false) or not (true).
419:                     */
420:                    private boolean stopped = true;
421:
422:                    /**
423:                     * Starts receiving thread if it is not running.
424:                     */
425:                    synchronized void start() {
426:                        if (startCounter == 0) {
427:                            if (stopped) {
428:                                stopped = false;
429:                                new Thread(this ).start();
430:                            }
431:                        }
432:                        startCounter++;
433:                    }
434:
435:                    /** Decrements number of receiving thread clients. */
436:                    synchronized void stop() {
437:                        startCounter--;
438:                    }
439:
440:                    /** Cancels receiving responses. */
441:                    synchronized void cancel() {
442:                        canceled = true;
443:                    }
444:
445:                    /**
446:                     * The <code>run()</code> method.
447:                     *
448:                     * @see java.lang.Runnable
449:                     */
450:                    public void run() {
451:                        while (true) {
452:                            synchronized (this ) {
453:                                if ((startCounter <= 0) || canceled) {
454:                                    startCounter = 0;
455:                                    stopped = true;
456:                                    break;
457:                                }
458:                            }
459:                            try {
460:                                processResponse();
461:                            } catch (IOException ioe) {
462:                                synchronized (this ) {
463:                                    if (startCounter <= 0 || canceled) {
464:                                        startCounter = 0;
465:                                        stopped = true;
466:                                        break;
467:                                    }
468:                                }
469:                                cancelAll(SDPResponseListener.IO_ERROR);
470:                            }
471:                        }
472:                    }
473:                }
474:
475:                /**
476:                 * This abstract class provides base functionality for all SDP
477:                 * transactions.
478:                 */
479:                private abstract class ServiceTransaction {
480:
481:                    /** PDU ID (see Bluetooth Specification 1.2 Vol 3 page 131) */
482:                    byte pduID;
483:                    /** Transcation ID used to identify this transaction. */
484:                    int transactionID;
485:                    /** Effective transaction ID. */
486:                    int effectiveTransactionID;
487:                    /** Length of all parameters. */
488:                    long parameterLength;
489:                    /** Continuation state used with partial responses. */
490:                    byte[] continuationState;
491:                    /** Listener to report request result to. */
492:                    SDPResponseListener listener;
493:
494:                    /**
495:                     * Class constructor.
496:                     *
497:                     * @param pduID protocol data unit ID
498:                     * @param transactionID transaction ID of the first request
499:                     * @param listener listener object which will receive
500:                     *                 completion and error notifications
501:                     */
502:                    ServiceTransaction(int pduID, int transactionID,
503:                            SDPResponseListener listener) {
504:                        this .pduID = (byte) pduID;
505:                        this .transactionID = transactionID;
506:                        effectiveTransactionID = newTransactionID();
507:                        this .listener = listener;
508:                    }
509:
510:                    /**
511:                     * Updates the effective transaction ID with a new value.
512:                     */
513:                    final void updateTransactionID() {
514:                        transactions
515:                                .remove(new Integer(effectiveTransactionID));
516:                        effectiveTransactionID = newTransactionID();
517:                        transactions.put(new Integer(effectiveTransactionID),
518:                                this );
519:                    }
520:
521:                    /**
522:                     * Starts this transaction.
523:                     *
524:                     * @throws IOException when an I/O error occurs
525:                     */
526:                    final void start() throws IOException {
527:                        addRef();
528:                        receiver.start();
529:
530:                        transactions.put(new Integer(effectiveTransactionID),
531:                                this );
532:
533:                        try {
534:                            synchronized (writeLock) {
535:                                rw.writeByte(pduID);
536:                                rw.writeShort((short) effectiveTransactionID);
537:                                rw.writeShort((short) (parameterLength + 1));
538:                                writeParameters();
539:                                rw.writeByte((byte) 0x00);
540:                                rw.flush();
541:                            }
542:                        } catch (IOException e) {
543:                            end();
544:                            throw e;
545:                        }
546:                    }
547:
548:                    /**
549:                     * Re-submits the original request with continuation state
550:                     * data received with the incomplete response.
551:                     *
552:                     * @throws IOException when an I/O error occurs
553:                     */
554:                    final void proceed() throws IOException {
555:                        updateTransactionID();
556:                        synchronized (writeLock) {
557:                            rw.writeByte(pduID);
558:                            rw.writeShort((short) effectiveTransactionID);
559:                            rw
560:                                    .writeShort((short) (parameterLength + 1 + continuationState.length));
561:                            writeParameters();
562:                            rw.writeByte((byte) continuationState.length);
563:                            rw.writeBytes(continuationState);
564:                            rw.flush();
565:                        }
566:                    }
567:
568:                    /**
569:                     * Extracts continuation state parameter.
570:                     *
571:                     * @return true if the continuation state is present,
572:                     *         false otherwise
573:                     * @throws IOException when an I/O error occurs
574:                     */
575:                    final boolean readContinuationState() throws IOException {
576:                        byte infoLength = rw.readByte();
577:                        if (infoLength == 0) {
578:                            continuationState = null;
579:                            return false;
580:                        }
581:                        continuationState = rw.readBytes(infoLength);
582:                        return true;
583:                    }
584:
585:                    /**
586:                     * Terminates this transaction and reports error to the listener.
587:                     *
588:                     * @param reason error code which will be reported
589:                     */
590:                    final void cancel(int reason) {
591:                        end();
592:                        listener.errorResponse(reason, "", transactionID);
593:                    }
594:
595:                    /**
596:                     * Ends this transaction by unregistering it in the outer class.
597:                     */
598:                    final void end() {
599:                        transactions
600:                                .remove(new Integer(effectiveTransactionID));
601:                        receiver.stop();
602:                        release();
603:                    }
604:
605:                    /**
606:                     * Reads error PDU, ends this transaction and reports listener the
607:                     * error code retrieved.
608:                     *
609:                     * @param length length of PDU's parameters
610:                     */
611:                    final void error(int length) throws IOException {
612:                        short errorCode = rw.readShort();
613:                        byte[] infoBytes = rw.readBytes(length - 2);
614:                        end();
615:                        listener.errorResponse(errorCode,
616:                                new String(infoBytes), transactionID);
617:                    }
618:
619:                    /**
620:                     * Processes this transaction by either re-submitting the original
621:                     * request if the last response was incomplete, or providing the
622:                     * listener with the results if the transaction was completed.
623:                     *
624:                     * @throws IOException when an I/O error occurs
625:                     */
626:                    final void process() throws IOException {
627:                        if (continuationState != null) {
628:                            try {
629:                                proceed();
630:                            } catch (IOException e) {
631:                                end();
632:                                throw e;
633:                            }
634:                        } else {
635:                            end();
636:                            complete();
637:                        }
638:                    }
639:
640:                    /**
641:                     * Writes transaction-specific parameters into the PDU.
642:                     *
643:                     * @throws IOException when an I/O error occurs
644:                     */
645:                    abstract void writeParameters() throws IOException;
646:
647:                    /**
648:                     * Reads transaction-specific parameters from the PDU.
649:                     *
650:                     * @param length length of PDU's parameters
651:                     * @throws IOException when an I/O error occurs
652:                     */
653:                    abstract void readParameters(int length) throws IOException;
654:
655:                    /**
656:                     * Completes the transaction by calling corresponding listener's
657:                     * method with the data retrieved.
658:                     */
659:                    abstract void complete();
660:
661:                }
662:
663:                /**
664:                 * Provides ServiceSearch transaction functionality.
665:                 */
666:                class ServiceSearchTransaction extends ServiceTransaction {
667:
668:                    /** ServiceSearchPattern (BT Spec 1.2 Vol 3 page 135). */
669:                    DataElement serviceSearchPattern;
670:                    /** Acquired service record handles. */
671:                    int[] handleList;
672:                    /** Current position in the handleList. */
673:                    int offset;
674:
675:                    /**
676:                     * Constructs ServiceSearchTransaction object.
677:                     */
678:                    ServiceSearchTransaction(int transactionID,
679:                            SDPResponseListener listener, UUID[] uuidSet) {
680:                        super (SDP_SERVICE_SEARCH_REQUEST, transactionID,
681:                                listener);
682:                        serviceSearchPattern = new DataElement(
683:                                DataElement.DATSEQ);
684:                        for (int i = 0; i < uuidSet.length; i++) {
685:                            serviceSearchPattern.addElement(new DataElement(
686:                                    DataElement.UUID, uuidSet[i]));
687:                        }
688:                        parameterLength = rw.getDataSize(serviceSearchPattern) + 2;
689:                    }
690:
691:                    /**
692:                     * Writes transaction-specific parameters into the PDU.
693:                     *
694:                     * @throws IOException when an I/O error occurs
695:                     */
696:                    void writeParameters() throws IOException {
697:                        rw.writeDataElement(serviceSearchPattern);
698:                        rw.writeShort((short) MAX_SERVICE_RECORD_COUNT);
699:                    }
700:
701:                    /**
702:                     * Reads transaction-specific parameters from the PDU.
703:                     *
704:                     * @param length length of PDU's parameters
705:                     * @throws IOException when an I/O error occurs
706:                     */
707:                    void readParameters(int length) throws IOException {
708:                        int totalServiceRecordCount = rw.readShort();
709:                        int currentServiceRecordCount = rw.readShort();
710:                        if (handleList == null && totalServiceRecordCount > 0) {
711:                            handleList = new int[totalServiceRecordCount];
712:                        }
713:                        for (int i = 0; i < currentServiceRecordCount; i++) {
714:                            handleList[offset] = rw.readInteger();
715:                            offset++;
716:                        }
717:                        readContinuationState();
718:                    }
719:
720:                    /**
721:                     * Completes the transaction by calling corresponding listener's
722:                     * method with the data retrieved.
723:                     */
724:                    void complete() {
725:                        listener.serviceSearchResponse(handleList,
726:                                transactionID);
727:                    }
728:                }
729:
730:                /**
731:                 * Provides ServiceAttribute transaction functionality.
732:                 */
733:                class ServiceAttributeTransaction extends ServiceTransaction {
734:
735:                    /** ServiceRecordHandle (BT Spec 1.2 Vol 3 page 138). */
736:                    int serviceRecordHandle;
737:                    /** AttributeIDList (BT Spec 1.2 Vol 3 page 139). */
738:                    DataElement attributeIDList;
739:                    /** AttributeList (BT Spec 1.2 Vol 3 page 140). */
740:                    byte[] attributes;
741:
742:                    /**
743:                     * Constructs ServiceAttributeTransaction object.
744:                     */
745:                    ServiceAttributeTransaction(int transactionID,
746:                            SDPResponseListener listener, int recordHandle,
747:                            int[] attrSet) {
748:                        super (SDP_SERVICE_ATTRIBUTE_REQUEST, transactionID,
749:                                listener);
750:                        serviceRecordHandle = recordHandle;
751:                        attributeIDList = new DataElement(DataElement.DATSEQ);
752:                        for (int i = 0; i < attrSet.length; i++) {
753:                            attributeIDList.addElement(new DataElement(
754:                                    DataElement.U_INT_2, attrSet[i]));
755:                        }
756:                        parameterLength = rw.getDataSize(attributeIDList) + 6;
757:                    }
758:
759:                    /**
760:                     * Writes transaction-specific parameters into the PDU.
761:                     *
762:                     * @throws IOException when an I/O error occurs
763:                     */
764:                    void writeParameters() throws IOException {
765:                        rw.writeInteger(serviceRecordHandle);
766:                        rw.writeShort((short) MAX_ATTRIBUTE_BYTE_COUNT);
767:                        rw.writeDataElement(attributeIDList);
768:                    }
769:
770:                    /**
771:                     * Reads transaction-specific parameters from the PDU.
772:                     *
773:                     * @param length length of PDU's parameters
774:                     * @throws IOException when an I/O error occurs
775:                     */
776:                    void readParameters(int length) throws IOException {
777:                        short byteCount = rw.readShort();
778:                        byte[] data = rw.readBytes(byteCount);
779:                        if (attributes == null) {
780:                            attributes = data;
781:                        } else {
782:                            byte[] temp = attributes;
783:                            attributes = new byte[temp.length + byteCount];
784:                            System.arraycopy(temp, 0, attributes, 0,
785:                                    temp.length);
786:                            System.arraycopy(data, 0, attributes, temp.length,
787:                                    byteCount);
788:                        }
789:                        readContinuationState();
790:                    }
791:
792:                    /**
793:                     * Completes the transaction by calling corresponding listener's
794:                     * method with the data retrieved.
795:                     */
796:                    void complete() {
797:                        DataElement attrList;
798:                        try {
799:                            attrList = des.restore(attributes);
800:                        } catch (IOException e) {
801:                            listener.serviceAttributeResponse(null, null,
802:                                    transactionID);
803:                            return;
804:                        }
805:                        int size = attrList.getSize() / 2;
806:                        if (size == 0) {
807:                            listener.serviceAttributeResponse(null, null,
808:                                    transactionID);
809:                            return;
810:                        }
811:                        Enumeration elements = (Enumeration) attrList
812:                                .getValue();
813:                        int[] attrIDs = new int[size];
814:                        DataElement[] attrValues = new DataElement[size];
815:                        for (int i = 0; elements.hasMoreElements(); i++) {
816:                            attrIDs[i] = (int) ((DataElement) elements
817:                                    .nextElement()).getLong();
818:                            attrValues[i] = ((DataElement) elements
819:                                    .nextElement());
820:                        }
821:                        listener.serviceAttributeResponse(attrIDs, attrValues,
822:                                transactionID);
823:                    }
824:                }
825:
826:                /**
827:                 * Provides ServiceSearchAttribute transaction functionality.
828:                 */
829:                class ServiceSearchAttributeTransaction extends
830:                        ServiceTransaction {
831:
832:                    /** ServiceSearchPattern (BT Spec 1.2 Vol 3 page 142). */
833:                    DataElement uuidData;
834:                    /** AttributeIDList (BT Spec 1.2 Vol 3 page 142). */
835:                    DataElement attrData;
836:                    /** AttributeLists (BT Spec 1.2 Vol 3 page 143). */
837:                    byte[] attributes;
838:
839:                    /**
840:                     * Constructs ServiceSearchAttributeTransaction object.
841:                     */
842:                    ServiceSearchAttributeTransaction(int transactionID,
843:                            SDPResponseListener listener, int[] attrSet,
844:                            UUID[] uuidSet) {
845:                        super (SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST,
846:                                transactionID, listener);
847:                        attrData = new DataElement(DataElement.DATSEQ);
848:                        uuidData = new DataElement(DataElement.DATSEQ);
849:                        for (int i = 0; i < attrSet.length; i++) {
850:                            attrData.addElement(new DataElement(
851:                                    DataElement.U_INT_2, attrSet[i]));
852:                        }
853:                        for (int i = 0; i < uuidSet.length; i++) {
854:                            uuidData.addElement(new DataElement(
855:                                    DataElement.UUID, uuidSet[i]));
856:                        }
857:                        parameterLength = rw.getDataSize(attrData)
858:                                + rw.getDataSize(uuidData) + 2;
859:                    }
860:
861:                    /**
862:                     * Writes transaction-specific parameters into the PDU.
863:                     *
864:                     * @throws IOException when an I/O error occurs
865:                     */
866:                    void writeParameters() throws IOException {
867:                        rw.writeDataElement(uuidData);
868:                        rw.writeShort((short) MAX_ATTRIBUTE_BYTE_COUNT);
869:                        rw.writeDataElement(attrData);
870:                    }
871:
872:                    /**
873:                     * Reads transaction-specific parameters from the PDU.
874:                     *
875:                     * @param length length of PDU's parameters
876:                     * @throws IOException when an I/O error occurs
877:                     */
878:                    void readParameters(int length) throws IOException {
879:                        short byteCount = rw.readShort();
880:                        byte[] data = rw.readBytes(byteCount);
881:                        if (attributes == null) {
882:                            attributes = data;
883:                        } else {
884:                            byte[] temp = attributes;
885:                            attributes = new byte[temp.length + byteCount];
886:                            System.arraycopy(temp, 0, attributes, 0,
887:                                    temp.length);
888:                            System.arraycopy(data, 0, attributes, temp.length,
889:                                    byteCount);
890:                        }
891:                        readContinuationState();
892:                    }
893:
894:                    /**
895:                     * Completes the transaction by calling corresponding listener's
896:                     * method with the data retrieved.
897:                     */
898:                    void complete() {
899:                        DataElement attrList;
900:                        try {
901:                            Enumeration attributeLists = (Enumeration) des
902:                                    .restore(attributes).getValue();
903:                            if (attributeLists.hasMoreElements()) {
904:                                attrList = (DataElement) attributeLists
905:                                        .nextElement();
906:                            } else {
907:                                listener.serviceSearchAttributeResponse(null,
908:                                        null, transactionID);
909:                                return;
910:                            }
911:                        } catch (IOException e) {
912:                            listener.serviceSearchAttributeResponse(null, null,
913:                                    transactionID);
914:                            return;
915:                        }
916:                        int size = attrList.getSize() / 2;
917:                        if (size == 0) {
918:                            listener.serviceSearchAttributeResponse(null, null,
919:                                    transactionID);
920:                            return;
921:                        }
922:                        Enumeration elements = (Enumeration) attrList
923:                                .getValue();
924:                        int[] attrIDs = new int[size];
925:                        DataElement[] attrValues = new DataElement[size];
926:                        for (int i = 0; elements.hasMoreElements(); i++) {
927:                            attrIDs[i] = (int) ((DataElement) elements
928:                                    .nextElement()).getLong();
929:                            attrValues[i] = ((DataElement) elements
930:                                    .nextElement());
931:                        }
932:                        listener.serviceSearchAttributeResponse(attrIDs,
933:                                attrValues, transactionID);
934:                    }
935:                }
936:
937:            }
938:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.