KickJava   Java API By Example, From Geeks To Geeks.

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


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.List JavaDoc;
22 import java.util.ArrayList JavaDoc;
23
24 import sync4j.framework.core.*;
25 import sync4j.framework.database.Database;
26
27 import sync4j.framework.protocol.ProtocolUtil;
28 import sync4j.framework.protocol.v11.ManagementActionsRequirements;
29 import sync4j.framework.protocol.v11.Errors;
30
31 /**
32  * Represents a Management Actions package of the SyncML DM protocol.
33  *
34  * The class is designed to be used in two times. First a <i>ManagementActions</i>
35  * is created and checked for validity and compliancy with the protocol. Than
36  * <i>getResponse()</i> can be used to get a response message for the given
37  * request. During the request validation process some information about the
38  * request message are cached into instance variables and used in <i>getResponse()</i>.<br>
39  *
40  * @author Stefano Fornari @ Funambol
41  *
42  * @version $Id: ManagementActions.java,v 1.1 2005/05/16 17:32:55 nichele Exp $
43  */

44 public class ManagementActions extends SyncPackage implements Flags, Errors {
45
46     /**
47      * Did the client challenge for authentication? If so, this property must
48      * contain server credentials.
49      */

50     private Cred serverCredentials;
51
52     /**
53      * Sets serverCredentials
54      *
55      * @param serverCredentials the new server credentials
56      */

57     public void setServerCredentials(Cred serverCredentials) {
58         this.serverCredentials = serverCredentials;
59     }
60
61     /**
62      * Gets serverCredentials
63      */

64     public Cred getServerCredentials() {
65         return serverCredentials;
66     }
67
68
69     // ------------------------------------------------------------ Constructors
70

71     /** Constructor. It creates a new instance from the message header and body.
72      * It also checks if the requirements specified by the SyncML DM protocol
73      * are met; if not a Sync4jException is thrown.
74      *
75      * @param syncHeader the header of the syncronization packet
76      * @param syncBody the body of the syncronization packet
77      *
78      * @throws Sync4jException in case SyncML requiremets are not respected
79      */

80     public ManagementActions(final SyncHdr syncHeader, final SyncBody syncBody)
81     throws ProtocolException {
82         super(syncHeader, syncBody);
83         checkRequirements();
84
85         checkSessionAbortRequired(syncBody);
86     }
87
88     // -------------------------------------------------------------- Properties
89

90     /**
91      * Caches the alert for session abort. It is set during the
92      * checking of the requirements.
93      */

94     private Alert sessionAbortAlert = null;
95
96     public boolean isSessionAbortRequired() {
97         return !(sessionAbortAlert == null);
98     }
99
100     /**
101      * Authorized status code - used in building response message
102      */

103     private int authorizedStatusCode = StatusCode.OK;
104
105     public void setAuthorizedStatusCode(int authorizedStatusCode) {
106         this.authorizedStatusCode = authorizedStatusCode;
107     }
108
109     /**
110      * The message mime type
111      */

112     private String JavaDoc mimeType = null;
113
114     /**
115      * Set message mime type
116      */

117     public void setMimeType(String JavaDoc mimeType) {
118         this.mimeType = mimeType;
119     }
120
121     /**
122       * Client authentication type
123       */

124      private String JavaDoc clientAuthType = null;
125
126      /**
127       * Sets clientAuthType
128       *
129       * @param authType client authentication type
130       */

131      public void setClientAuthType(String JavaDoc authType) {
132          this.clientAuthType = authType;
133      }
134
135
136      /**
137       * Next nonce for HMAC/MD5 authentication
138       */

139      private NextNonce nextNonce = null;
140
141      /**
142       * Sets nextNonce
143       *
144       * @param nextNonce the next nonce
145       */

146      public void setNextNonce(NextNonce nextNonce) {
147          this.nextNonce = nextNonce;
148     }
149
150     /**
151      * The management commands the server wants to sent to the client.
152      */

153     private AbstractCommand[] managementCommands = null;
154
155     /**
156      * Returns the serverModifications property.
157      *
158      * @return the serverModifications property.
159      */

160     public AbstractCommand[] getManagementCommands() {
161         return this.managementCommands;
162     }
163
164     /**
165      * Sets the managementCommands property.
166      *
167      * @param managementCommands new value
168      */

169     public void setManagementCommands(AbstractCommand[] managementCommands) {
170         this.managementCommands = managementCommands;
171     }
172
173     /**
174      * Caches the commands sent by the client. It is set during the
175      * checking of the requirements.
176      */

177     private AbstractCommand[] clientCommands = null;
178
179     /**
180      * Returns the clientCommands property.
181      *
182      * @return the clientCommands property.
183      */

184     public AbstractCommand[] getClientCommands() {
185         return clientCommands;
186     }
187
188     /**
189       * Sets the clientCommands property.
190       *
191       * @param commands the commands to set
192       */

193      public void setClientCommands(AbstractCommand[] commands) {
194          this.clientCommands = commands;
195      }
196
197
198     // ---------------------------------------------------------- Public methods
199

200     /**
201      * Checks that all requirements regarding the header of the initialization
202      * packet are respected.
203      *
204      * @throws ProtocolException if header requirements are not respected
205      */

206     public void checkHeaderRequirements() throws ProtocolException {
207         ManagementActionsRequirements.checkDTDVersion (syncHeader.getVerDTD() );
208         ManagementActionsRequirements.checkProtocolVersion(syncHeader.getVerProto() );
209         ManagementActionsRequirements.checkSessionId (syncHeader.getSessionID());
210         ManagementActionsRequirements.checkMessageId (syncHeader.getMsgID() );
211         ManagementActionsRequirements.checkTarget (syncHeader.getTarget() );
212         ManagementActionsRequirements.checkSource (syncHeader.getSource() );
213     }
214
215     /**
216      * Checks that all requirements regarding the body of the initialization
217      * packet are respected.
218      *
219      * @throws ProtocolException if body requirements are not respected
220      */

221     public void checkBodyRequirements() throws ProtocolException {
222         // NOTE: initializes the clientCommands property
223
clientCommands = (AbstractCommand[])syncBody.getCommands().toArray(new AbstractCommand[0]);
224
225         //
226
// If there is a Results command, check it
227
//
228
List JavaDoc results = ProtocolUtil.filterCommands(clientCommands, Results.class);
229
230         if (results.size() > 0) {
231             ManagementActionsRequirements.checkResults(results);
232         }
233     }
234
235     /**
236      * Filters client commands for Results and return them
237      *
238      * @return an array of Results commands
239      */

240     public Results[] getResults() {
241         ArrayList JavaDoc ret =
242             ProtocolUtil.filterCommands(clientCommands, Results.class);
243
244         return (Results[])ret.toArray(new Results[ret.size()]);
245     }
246
247     // ----------------------------------------------------------- getResponse()
248

249     /**
250      * Constructs a proper response message.<p>
251      * The sync package to the client has the following purposes:
252      * <ul>
253      * <li>To inform the client about the results of sync analysis.
254      * <li>To inform about all data modifications, which have happened in the
255      * server since the previous time when the server has sent the
256      * modifications to the client.
257      * </ul>
258      *
259      * @param msgId the msg id of the response
260      * @return the response message
261      *
262      * @throws ProtocolException in case of error or inconsistency
263      */

264     public SyncML getResponse(String JavaDoc msgId) throws ProtocolException {
265         ArrayList JavaDoc responseCommandList = new ArrayList JavaDoc();
266
267         if (idGenerator == null) {
268             throw new NullPointerException JavaDoc("The id generator is null. Please set a value for idGenerator");
269         }
270
271         //
272
// Constructs all required response commands.
273
//
274
// NOTE: if NoResp is specified in the header element, than no
275
// response commands must be returned regardless NoResp is
276
// specified or not in subsequent commands
277
//
278
if (syncHeader.isNoResp() == false) {
279
280             TargetRef[] targetRefs = new TargetRef[] { new TargetRef(syncHeader.getTarget().getLocURI()) };
281             SourceRef[] sourceRefs = new SourceRef[] { new SourceRef(syncHeader.getSource().getLocURI()) };
282
283
284             //
285
// If the client uses HMAC, a Chal element must be returned
286
//
287
Chal chal = null;
288
289             if (Constants.AUTH_TYPE_HMAC.equalsIgnoreCase(clientAuthType)) {
290                 //
291
// We must return a chal with the next nonce
292
//
293
chal = Chal.getHMACChal();
294                 chal.setNextNonce(nextNonce);
295             }
296
297             Status statusCommand = new Status(
298                                               idGenerator.next() ,
299                                               syncHeader.getMsgID() ,
300                                               "0" /* command ref */ ,
301                                               "SyncHdr" /* see SyncML specs */ ,
302                                               targetRefs ,
303                                               sourceRefs ,
304                                               null /* credential */ ,
305                                               chal /* challenge */ ,
306                                               new Data(authorizedStatusCode) ,
307                                               new Item[0]
308                                           );
309
310             responseCommandList.add(statusCommand);
311         }
312
313         if (isFlag(Flags.FLAG_SERVER_ABORT_REQUIRED)) {
314
315             //
316
// Add only Alert for abort the session
317
//
318
Alert abortAlert = new Alert(idGenerator.next(),
319                                          false,
320                                          null,
321                                          AlertCode.SESSION_ABORT,
322                                          new Item[0]);
323
324             responseCommandList.add(abortAlert);
325
326         } else {
327
328             //
329
// Adds status for all client command
330
//
331
int numClientCommand = clientCommands.length;
332             AbstractCommand command = null;
333             TargetRef[] targetRefs = null;
334             SourceRef[] sourceRefs = null;
335             Status statusCommand = null;
336             boolean hasLargeObject = false;
337             Long JavaDoc itemSize = null;
338             for (int i = 0; i < numClientCommand; i++) {
339
340                 command = clientCommands[i];
341
342                 if (command.isNoResp() || (command instanceof Status)) {
343                     continue;
344                 }
345
346                 int status = StatusCode.OK;
347                 hasLargeObject = ProtocolUtil.hasLargeObject(command);
348
349                 //
350
// For Results:
351
// - if this not has a large object:
352
// if the item has a size specified this must match with the real dimension
353
// of the data
354
// otherwise
355
// no response is necessary.
356
// - if Results has a large object the server must return a status code (213)
357
//
358
if (command instanceof Results) {
359                     ArrayList JavaDoc itemsList = ( (Results)command).getItems();
360                     if (itemsList.size() == 1) {
361                         itemSize = Util.getItemSize( (Item) (itemsList.get(0)));
362                     }
363
364                     if (!hasLargeObject) {
365                         if (itemSize != null) {
366                             Long JavaDoc realSize = Util.getRealItemSize( (Item) (itemsList.get(0)), mimeType);
367                             if (itemSize.equals(realSize)) {
368                                 // no status necessary
369
continue;
370                             } else {
371                                 status = StatusCode.OBJECT_SIZE_MISMATCH;
372                             }
373                         } else {
374                             continue;
375                         }
376                     } else {
377                         if (itemSize == null) {
378                             // A large object is sent from the client
379
// without the meta size
380
status = StatusCode.INCOMPLETE_COMMAND;
381                         } else {
382                             status = StatusCode.CHUNKED_ITEM_ACCEPTED;
383                         }
384                     }
385                 }
386
387                 //
388
// NOTE: currently all items returns always the same status,
389
// therefore no targetRefs/sourceRefs must be specified
390
// (see syncml_represent_v11_20020215).
391
//
392
targetRefs = null;
393                 sourceRefs = null;
394
395                 String JavaDoc commandReference = command.getCmdID().getCmdID();
396
397                 Item[] items = new Item[0];
398
399                 statusCommand = new Status(
400                     idGenerator.next(),
401                     syncHeader.getMsgID(),
402                     commandReference,
403                     command.getName(),
404                     targetRefs,
405                     sourceRefs,
406                     null
407                     /* credential */
408                     ,
409                     null
410                     /* challenge */
411                     ,
412                     new Data(status),
413                     items
414                                 );
415
416                 responseCommandList.add(statusCommand);
417
418             } // next i
419

420             Status statusForSessionAbort = null;
421
422             if (sessionAbortAlert != null) {
423
424                 TargetRef targerRef = null;
425                 SourceRef sourceRef = null;
426                 statusForSessionAbort = new Status(
427                     idGenerator.next(),
428                     syncHeader.getMsgID(),
429                     sessionAbortAlert.getCmdID().getCmdID(),
430                     "Alert",
431                     targerRef,
432                     sourceRef,
433                     null, // Credential
434
null, // challenge
435
new Data(StatusCode.OK),
436                     new Item[0]
437                                         );
438
439                 responseCommandList.add(statusForSessionAbort);
440             } else {
441                 if (!isFlag(FLAG_MORE_MSG_REQUIRED)) {
442                     //
443
// Include management action commands
444
//
445
for (int i = 0; ( (managementCommands != null) && (i < managementCommands.length));
446                                  ++i) {
447                         responseCommandList.add(managementCommands[i]);
448                     }
449                 } else {
450                     //
451
// waiting for more msg from the client.
452
// Send alert code 1222
453
//
454
Alert moreMsg = new Alert(
455                         idGenerator.next(), // cmdId
456
false, // noResp
457
null, // cred
458
AlertCode.MORE_DATA, // data
459
null // item[]
460
);
461                     responseCommandList.add(moreMsg);
462                     unsetFlag(FLAG_FINAL_MESSAGE);
463                 }
464             }
465         }
466
467         //
468
// Constructs return message
469
//
470
Target target = new Target(syncHeader.getSource().getLocURI(),
471                                    syncHeader.getSource().getLocName());
472         Source source = new Source(syncHeader.getTarget().getLocURI(),
473                                    syncHeader.getTarget().getLocName());
474
475         SyncHdr responseHeader = new SyncHdr (
476                                         getDTDVersion() ,
477                                         getProtocolVersion() ,
478                                         syncHeader.getSessionID() ,
479                                         msgId ,
480                                         target ,
481                                         source ,
482                                         null /* response URI */ ,
483                                         false ,
484                                         serverCredentials ,
485                                         null /* meta data */
486                                     );
487
488         AbstractCommand[] commands = null;
489         int numCommand = responseCommandList.size();
490         if (numCommand == 0) {
491             commands = new AbstractCommand[1];
492         } else {
493             commands = new AbstractCommand[numCommand];
494         }
495         for (int i=0; i < numCommand; i++) {
496             commands[i] = (AbstractCommand)responseCommandList.get(i);
497         }
498
499         SyncBody responseBody = new SyncBody(
500                                     commands,
501                                     isFlag(FLAG_FINAL_MESSAGE) /* final */
502                                 );
503
504         try {
505             return new SyncML(responseHeader, responseBody);
506         } catch (RepresentationException e) {
507             //
508
// It should never happen !!!!
509
//
510
throw new ProtocolException("Unexpected error", e);
511         }
512     }
513
514     // --------------------------------------------------------- Private methods
515
/**
516      * Checks if in the request there is a alert code for session abort. If present,
517      * cache it in sessionAbortAlert instance variable.
518      * @param body the SyncBody to check
519      */

520     private void checkSessionAbortRequired(SyncBody syncBody) {
521
522         AbstractCommand[] allClientCommands =
523             (AbstractCommand[])syncBody.getCommands().toArray(
524             new AbstractCommand[0]);
525
526
527         //
528
// Extracts the Alert command
529
//
530
ArrayList JavaDoc alertList = ProtocolUtil.filterCommands(allClientCommands,
531             Alert.class);
532         int size = alertList.size();
533         Alert[] alerts = new Alert[size];
534         for (int i = 0; i < size; i++) {
535             alerts[i] = (Alert)alertList.get(i);
536
537             if (alerts[i].getData() == AlertCode.SESSION_ABORT) {
538                 // session abort required
539
sessionAbortAlert = alerts[i];
540                 return ;
541             }
542         }
543         sessionAbortAlert = null;
544     }
545
546 }
Popular Tags