KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sync4j > framework > protocol > ManagementInitialization


1 /**
2  * Copyright (C) 2003-2005 Funambol
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18
19 package sync4j.framework.protocol;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.Hashtable JavaDoc;
23
24 import sync4j.framework.core.*;
25
26 import sync4j.framework.protocol.SyncPackage;
27 import sync4j.framework.protocol.ProtocolUtil;
28 import sync4j.framework.protocol.v11.Errors;
29 import sync4j.framework.protocol.v11.InitializationRequirements;
30
31 import sync4j.framework.core.dm.ddf.DevInfo;
32 import java.util.Collections JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import sync4j.framework.tools.ArrayUtils;
37
38
39 /**
40  * Represents the Initialization package of the SyncML DM protocol.
41  *
42  * Example of use:
43  * <pre>
44  * ManagementInitialization init = new ManagementInitialization(header, body);
45  * ... do something ...
46  * init.setManagementCommands(commands);
47  * init.setAuthorizedStatusCode(StatusCode.AUTHENTICATION_ACCEPTED);
48  * ... other initializations ...
49  * Message response = init.getResponse();
50  * </pre>
51  *
52  * @author Stefano Fornari @ Funambol
53  *
54  * @version $Id: ManagementInitialization.java,v 1.1 2005/05/16 17:32:55 nichele Exp $
55  *
56  * @see SyncPackage
57  */

58 /**
59  * @TODO: extract the client Chal if given and store it in clientChal
60  */

61 public class ManagementInitialization
62 extends SyncPackage
63 implements Errors {
64
65     // ------------------------------------------------------------ Private data
66

67     /**
68      * Caches the commands sent by the client.It is set during the
69      * checking of the requirements.
70      */

71     private AbstractCommand[] clientCommands = null;
72
73     public AbstractCommand[] getClientCommands() {
74         return clientCommands;
75     }
76
77     /**
78      * Adds the given abstract command to clientCommands
79      * @param command the command to add
80      */

81     public void addClientCommand(AbstractCommand[] command) {
82         Object JavaDoc[] obj = (AbstractCommand[])ArrayUtils.mergeArrays(clientCommands, command,
83             AbstractCommand.class);
84         clientCommands = (AbstractCommand[])obj;
85     }
86
87     /**
88      * Caches the alert command sent by the client. It is set during the
89      * checking of the requirements.
90      */

91     private Alert clientAlert = null;
92
93     public Alert getClientAlert() {
94         return clientAlert;
95     }
96
97
98     /**
99      * Authorized status code - used in building response message
100      */

101     private int authorizedStatusCode = -1;
102
103     public void setAuthorizedStatusCode(int authorizedStatusCode) {
104         this.authorizedStatusCode = authorizedStatusCode;
105     }
106
107     /**
108      * Keeps the given DevInfo DM object given by the SyncML DM client
109      */

110     private DevInfo devInfo = null;
111
112     /**
113      * Returns the DevInfo DM object given by the SyncML DM client
114      *
115      * @return the DevInfo DM object given by the SyncML DM client
116      */

117     public DevInfo getDevInfo() {
118         return devInfo;
119     }
120
121     /**
122      * Management commands to be performed on the client
123      */

124     AbstractCommand[] managementCommands;
125
126     /**
127      * Sets managementCommands
128      *
129      * @param commands the management commands
130      */

131     public void setManagementCommands(AbstractCommand[] commands) {
132        managementCommands = commands;
133     }
134
135     public AbstractCommand[] getManagementCommands() {
136         return managementCommands;
137     }
138
139     /**
140      * Did the client challenge for authentication? If so, this property contains
141      * client Chal
142      */

143     private Chal clientChal = null;
144
145     /**
146      * Gets clientChal
147      *
148      * @return the given client Chal
149      */

150     public Chal getClientChal() {
151         return clientChal;
152     }
153
154     /**
155      * Did the client challenge for authentication? If so, this property must
156      * contain server credentials.
157      */

158     private Cred serverCredentials;
159
160     /**
161      * Sets serverCredentials
162      *
163      * @param serverCredentials the new server credentials
164      */

165     public void setServerCredentials(Cred serverCredentials) {
166         this.serverCredentials = serverCredentials;
167     }
168
169     /**
170      * Gets serverCredentials
171      */

172     public Cred getServerCredentials() {
173         return serverCredentials;
174     }
175
176     /**
177      * Server authentication type
178      */

179     private String JavaDoc serverAuthType = null;
180
181     /**
182      * Sets serverAuthType
183      *
184      * @param authType server authentication type
185      */

186     public void setServerAuthType(String JavaDoc authType) {
187         this.serverAuthType = authType;
188     }
189
190     /**
191      * Supported auth type
192      */

193     private String JavaDoc supportedAuthType = null;
194
195
196     public void setSupportedAuthType(String JavaDoc supportedAuthType) {
197         this.supportedAuthType = supportedAuthType;
198     }
199
200
201     /**
202       * Client authentication type
203       */

204      private String JavaDoc clientAuthType = null;
205
206      /**
207       * Sets clientAuthType
208       *
209       * @param authType client authentication type
210       */

211      public void setClientAuthType(String JavaDoc authType) {
212          this.clientAuthType = authType;
213      }
214
215
216     /**
217      * Next nonce for MD5 authentication
218      */

219     private NextNonce nextNonce = null;
220
221     /**
222      * Sets nextNonce
223      *
224      * @param nextNonce the next nonce
225      */

226     public void setNextNonce(NextNonce nextNonce) {
227         this.nextNonce = nextNonce;
228     }
229
230     // ---------------------------------------------------------- Command status
231

232     /**
233      * The map containing the status of the commands
234      */

235     private Hashtable JavaDoc commandStatus = new Hashtable JavaDoc();
236
237     /**
238      * Sets the status code for the given command.
239      *
240      * @param cmd the command
241      * @param statusCode the status code
242      */

243     public void setStatusCodeForCommand(AbstractCommand cmd, int statusCode) {
244         setStatusCodeForCommand(cmd.getCmdID().getCmdID(), statusCode);
245     }
246
247     /**
248      * Sets the status code for the command identified by the given id.
249      *
250      * @param cmdId the command id
251      * @param statusCode the status code
252      */

253     public void setStatusCodeForCommand(String JavaDoc cmdId, int statusCode) {
254         commandStatus.put(cmdId, new Integer JavaDoc(statusCode));
255     }
256
257     /**
258      * Returns the status code for the given command. The status code must be
259      * previously set with <i>setStatusCodeForCommand()</i>. If no status code
260      * is associated to the given command, the default status code is returned.
261      *
262      * @param cmd the command
263      * @param defaultCode the default status code
264      *
265      * @return the status code for the command if previously set, the default
266      * status code otherwise
267      */

268     public int getStatusCodeForCommand(AbstractCommand cmd, int defaultCode) {
269         String JavaDoc cmdId = cmd.getCmdID().getCmdID();
270
271         return getStatusCodeForCommand(cmdId, defaultCode);
272
273     }
274
275     /**
276      * The same as <i>getStatusCodeForCommand(AbstractCommand, int) but passing
277      * in the command id instead of the command.
278      *
279      * @param cmdId the command id
280      * @param defaultCode
281      *
282      * @return the status code for the command if previously set, the default
283      * status code otherwise
284      */

285     public int getStatusCodeForCommand(String JavaDoc cmdId, int defaultCode) {
286         Integer JavaDoc statusCode = (Integer JavaDoc)commandStatus.get(cmdId);
287
288         return (statusCode == null) ? defaultCode : statusCode.intValue();
289     }
290
291
292     // ------------------------------------------------------------ Constructors
293

294     /**
295       *
296       * @param syncHeader the header of the syncronization packet
297       * @param syncBody the body of the syncronization packet
298       *
299       * @throws ProtocolException
300       */

301     public ManagementInitialization(final SyncHdr syncHeader,
302                                     final SyncBody syncBody )
303     throws ProtocolException {
304         super(syncHeader, syncBody);
305         checkRequirements();
306
307     }
308
309     // ---------------------------------------------------------- Public methods
310

311     /**
312      * Checks that all requirements regarding the header of the initialization
313      * packet are respected.
314      *
315      * @throws ProtocolException
316      */

317     public void checkHeaderRequirements()
318     throws ProtocolException {
319         InitializationRequirements.checkDTDVersion (syncHeader.getVerDTD() );
320         InitializationRequirements.checkProtocolVersion(syncHeader.getVerProto());
321         InitializationRequirements.checkSessionId (syncHeader.getSessionID());
322         InitializationRequirements.checkMessageId (syncHeader.getMsgID() );
323         InitializationRequirements.checkTarget (syncHeader.getTarget() );
324         InitializationRequirements.checkSource (syncHeader.getSource() );
325     }
326
327     /**
328      * Checks that all requirements regarding the body of the initialization
329      * packet are respected.
330      *
331      * @throws ProtocolException
332      */

333     public void checkBodyRequirements()
334     throws ProtocolException {
335
336         AbstractCommand[] allClientCommands =
337             (AbstractCommand[])syncBody.getCommands().toArray(
338             new AbstractCommand[0]);
339
340         //
341
// Extracts the Alert command
342
//
343
ArrayList JavaDoc alertList = ProtocolUtil.filterCommands(allClientCommands,
344             Alert.class);
345
346         int size = alertList.size();
347
348         // Checks if in the list of the alerts there is a alert for session abort.
349
// If so, ignore other alert
350
for (int i = 0; i < size; i++) {
351             clientAlert = (Alert)alertList.get(i);
352
353             if (clientAlert.getData() == AlertCode.SESSION_ABORT) {
354                 // session abort
355
setFlag(FLAG_SESSION_ABORT_REQUIRED);
356                 break;
357             } else {
358
359             }
360         }
361
362         //
363
// NOTE: we do not need to check for alert commands, since in DM we can
364
// have Client Event Alerts (even if no processing is defined).
365
//
366

367         //
368
// check if there is a Replace command with device info. If so,
369
// caches device info. Plus, if the message is set as "final" check
370
// that the it contains the Replace command.
371
//
372
if (isFinal()) {
373             ArrayList JavaDoc replaceCommands =
374                 ProtocolUtil.filterCommands(allClientCommands, Replace.class);
375
376             if (replaceCommands.size() == 0) {
377                 throw new ProtocolException(ERRMSG_MISSING_REPLACE);
378             }
379             InitializationRequirements.checkDeviceInfo( (Replace)replaceCommands.get(0));
380
381             //
382
// It's ok, cache the devInfo object and clientCommands
383
//
384
devInfo = ProtocolUtil.devInfoFromReplace( (Replace)replaceCommands.get(0));
385         }
386
387         clientCommands = allClientCommands;
388     }
389
390
391
392     /**
393      * Constructs a proper response message.<br>
394      * NOTES
395      * <ul>
396      * <li> If server capabilities are not required, they are not sent (in
397      * the SyncML protocol the server MAY send not required capabilities)
398      * </ul>
399      *
400      * @param msgId the msg id of the response
401      * @return the response message
402      *
403      * @throws ProtocolException in case of error or inconsistency
404      */

405     public SyncML getResponse(String JavaDoc msgId) throws ProtocolException {
406         ArrayList JavaDoc responseCommandList = new ArrayList JavaDoc();
407
408         ArrayList JavaDoc clientCommandList = new ArrayList JavaDoc(Arrays.asList(clientCommands));
409
410         //
411
// Constructs all required response commands.
412
//
413
// NOTE: if NoResp is specified in the header element, than no
414
// response commands must be returned regardless NoResp is
415
// specified or not in subsequent commands
416
//
417

418         if (syncHeader.isNoResp() == false) {
419             //
420
// Session authorization
421
//
422
TargetRef[] targetRefs = new TargetRef[] { new TargetRef(syncHeader.getTarget().getLocURI()) };
423             SourceRef[] sourceRefs = new SourceRef[] { new SourceRef(syncHeader.getSource().getLocURI()) };
424
425             //
426
// If the session is not authenticated, a Chal element must be returned
427
//
428
Chal chal = null;
429
430             if (!isFlag(Flags.FLAG_CHAL_NOT_REQUIRED)) {
431
432                 switch (authorizedStatusCode) {
433                     case StatusCode.OK:
434
435                         //
436
// Using HMAC the status code is 200 and the server must
437
// return a chal with new nonce
438
//
439
if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_HMAC)) {
440                             chal = Chal.getHMACChal();
441                             chal.setNextNonce(nextNonce);
442                         }
443
444                         break;
445
446                     case StatusCode.AUTHENTICATION_ACCEPTED:
447
448                         //
449
// The MD5 and HMAC authentication always requires the chal element
450
//
451
if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_MD5)) {
452                             chal = Chal.getMD5Chal();
453                             chal.setNextNonce(nextNonce);
454                         } else if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_HMAC)) {
455                             chal = Chal.getHMACChal();
456                             chal.setNextNonce(nextNonce);
457                         }
458
459                         break;
460                     case StatusCode.INVALID_CREDENTIALS:
461
462                         if (clientAuthType != null && supportedAuthType.indexOf(clientAuthType) != -1) {
463                             if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_BASIC)) {
464                                 chal = Chal.getBasicChal();
465                             } else if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_CLEAR)) {
466                                 chal = Chal.getClearChal();
467                             } else if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_MD5)) {
468                                 chal = Chal.getMD5Chal();
469                                 chal.setNextNonce(nextNonce);
470                             } else if (clientAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_HMAC)) {
471                                 chal = Chal.getHMACChal();
472                                 chal.setNextNonce(nextNonce);
473                             }
474
475                             break;
476                         }
477
478                     case StatusCode.MISSING_CREDENTIALS:
479
480                         if (serverAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_BASIC)) {
481                             chal = Chal.getBasicChal();
482                         } else if (serverAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_CLEAR)) {
483                             chal = Chal.getClearChal();
484                         } else if (serverAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_MD5)) {
485                             chal = Chal.getMD5Chal();
486                             chal.setNextNonce(nextNonce);
487                         } else if (serverAuthType.equalsIgnoreCase(Constants.AUTH_TYPE_HMAC)) {
488                             chal = Chal.getHMACChal();
489                             chal.setNextNonce(nextNonce);
490                         }
491
492                         break;
493
494                     default:
495
496                 }
497             }
498
499             Status statusCommand = new Status(
500                                     idGenerator.next() ,
501                                     syncHeader.getMsgID() ,
502                                     "0" /* command ref */ ,
503                                     "SyncHdr" /* see SyncML specs */ ,
504                                     targetRefs ,
505                                     sourceRefs ,
506                                     null /* credential */ ,
507                                     chal ,
508                                     new Data(String.valueOf(authorizedStatusCode)),
509                                     new Item[0]
510                                    );
511
512             responseCommandList.add(statusCommand);
513
514             //
515
// Status for each command that requested it (it is supposed each
516
// command has bean already checked).
517
//
518
int numClientCommand = clientCommandList.size();
519
520             AbstractCommand command = null;
521
522             for (int i=0; i<numClientCommand; i++) {
523
524                 command = (AbstractCommand)clientCommandList.get(i);
525
526                 if (command.isNoResp() || (command instanceof Status)) {
527                     continue;
528                 }
529
530                 //
531
// NOTE: currently all items returns always the same status,
532
// therefore no targetRefs/sourceRefs must be specified
533
// (see syncml_represent_v11_20020215).
534
//
535
targetRefs = null;
536                 sourceRefs = null;
537
538                 String JavaDoc commandReference = command.getCmdID().getCmdID();
539                 int status = getStatusCodeForCommand(command, StatusCode.OK);
540
541                 Item[] items = new Item[0];
542
543                 statusCommand = new Status(
544                                     idGenerator.next() ,
545                                     syncHeader.getMsgID() ,
546                                     commandReference ,
547                                     command.getName() ,
548                                     targetRefs ,
549                                     sourceRefs ,
550                                     null /* credential */ ,
551                                     null /* challenge */ ,
552                                     new Data(status) ,
553                                     items
554                                 );
555
556                 responseCommandList.add(statusCommand);
557
558             } // next i
559
} // end if syncHeader.getNoResponse() == false
560

561
562         // in this implementation i add one status for all clientCommand, then
563
// remove all clientCommand
564
clientCommandList.removeAll(clientCommandList);
565
566
567         // re-set the clientCommands array with the commands again in the list
568
clientCommands = (AbstractCommand[])clientCommandList.toArray(new AbstractCommand[] {});
569
570         //
571
// Add management commands
572
//
573
if (!isFlag(FLAG_SESSION_ABORT_REQUIRED)) {
574             if (managementCommands != null) {
575                 for (int i = 0; i < managementCommands.length; ++i) {
576                     responseCommandList.add(managementCommands[i]);
577                 }
578             }
579         }
580
581
582         //
583
// Constructs return message
584
//
585
Target target = new Target(syncHeader.getSource().getLocURI(),
586                                    syncHeader.getSource().getLocName());
587         Source source = new Source(syncHeader.getTarget().getLocURI(),
588                                    syncHeader.getTarget().getLocName());
589         SyncHdr responseHeader = new SyncHdr (
590                                         getDTDVersion() ,
591                                         getProtocolVersion() ,
592                                         syncHeader.getSessionID(),
593                                         msgId ,
594                                         target ,
595                                         source ,
596                                         null /* response URI */ ,
597                                         false ,
598                                         serverCredentials ,
599                                         syncHeader.getMeta()
600                                     );
601
602         int size = responseCommandList.size();
603         AbstractCommand [] aCommands = new AbstractCommand[size];
604         for (int i=0; i < size; i++) {
605             aCommands[i] = (AbstractCommand)responseCommandList.get(i);
606
607             if (authorizedStatusCode != StatusCode.AUTHENTICATION_ACCEPTED) {
608                 if (aCommands[i] instanceof Status) {
609                     Status sc = (Status)aCommands[i];
610                     sc.setData(new Data(String.valueOf(authorizedStatusCode)));
611                 }
612             }
613
614         }
615
616         SyncBody responseBody = new SyncBody(
617                                    aCommands,
618                                    isFlag(Flags.FLAG_FINAL_MESSAGE)
619                                 );
620
621         try {
622             return new SyncML(responseHeader, responseBody);
623         } catch (RepresentationException e) {
624             //
625
// It should never happen !!!!
626
//
627
throw new ProtocolException("Unexpected error", e);
628         }
629     }
630
631
632     public void setRequest(SyncML request) {
633         this.syncHeader = request.getSyncHdr();
634         this.syncBody = request.getSyncBody();
635     }
636
637
638
639     /**
640      * Returns true if a session abort is required
641      * @return true if a session abort is required, false otherwise
642      */

643     public boolean isSessionAbortRequired() {
644         return isFlag(Flags.FLAG_SESSION_ABORT_REQUIRED);
645     }
646
647     // --------------------------------------------------------- Private methods
648

649
650 }
Popular Tags