Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / service / resource-encapsulation / android / service / src / main / java / org / iotivity / service / server / RcsResourceObject.java
1 /******************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20 /**
21  * @file   RCSResourceObject.java
22  *
23  *  This file contains the resource object APIs provided to the developers.
24  *        RCSResourceObject is a part of the server builder module.
25  *
26  */
27
28 package org.iotivity.service.server;
29
30 import java.lang.ref.WeakReference;
31
32 import org.iotivity.service.RcsDestroyedObjectException;
33 import org.iotivity.service.RcsException;
34 import org.iotivity.service.RcsIllegalStateException;
35 import org.iotivity.service.RcsObject;
36 import org.iotivity.service.RcsPlatformException;
37 import org.iotivity.service.RcsResourceAttributes;
38 import org.iotivity.service.RcsValue;
39
40 /**
41  * RCSResourceObject represents a resource. It handles any requests from clients
42  * automatically with attributes.
43  * <p>
44  * It also provides an auto notification mechanism that notifies to the
45  * observers. Requests are handled automatically by defaultAction of
46  * {@link RcsGetResponse} and {@link RcsSetResponse}. You can override them and
47  * send your own response with {@link GetRequestHandler} and
48  * {@link SetRequestHandler}.
49  * <p>
50  * For simple resources, they are simply required to notify whenever attributes
51  * are changed by a set request. In this case, add an
52  * {@link OnAttributeUpdatedListener} with a key interested in instead of
53  * overriding {@link SetRequestHandler}.
54  *
55  * @see Builder
56  */
57 public final class RcsResourceObject extends RcsObject {
58     /**
59      * This is a builder to create resource with properties and attributes.
60      *
61      * The resource will be observable and discoverable by default, to make them
62      * disable
63      * set these properties explicitly with setDiscoverable and setObservable.
64      *
65      */
66     public static class Builder {
67         private final String          mUri;
68         private final String          mType;
69         private final String          mInterface;
70         private boolean               mIsObservable    = true;
71         private boolean               mIsDiscovervable = true;
72         private RcsResourceAttributes mAttributes;
73
74         /**
75          * Constructs a Builder.
76          *
77          * @param uri
78          *            resource uri
79          * @param resourceType
80          *            resource type
81          * @param resourceInterface
82          *            resource interface
83          *
84          * @throws NullPointerException
85          *             if any parameter is null
86          */
87         public Builder(String uri, String resourceType,
88                 String resourceInterface) {
89             if (uri == null) {
90                 throw new NullPointerException("uri is null.");
91             }
92             if (resourceType == null) {
93                 throw new NullPointerException("resourceType is null.");
94             }
95             if (resourceInterface == null) {
96                 throw new NullPointerException("resourceInterface is null.");
97             }
98
99             mUri = uri;
100             mType = resourceType;
101             mInterface = resourceInterface;
102         }
103
104         /**
105          * Sets whether the resource is discoverable.
106          *
107          * @param isDiscoverable
108          *            whether to be discoverable or not
109          *
110          */
111         public Builder setDiscoverable(boolean isDiscoverable) {
112             mIsDiscovervable = isDiscoverable;
113             return this;
114         }
115
116         /**
117          * Sets the observable(OC_OBSERVABLE) property of the resource.
118          *
119          * @param isObservable
120          *            whether to be observable or not
121          *
122          */
123         public Builder setObservable(boolean isObservable) {
124             mIsObservable = isObservable;
125             return this;
126         }
127
128         /**
129          * Sets attributes foe the resource.
130          *
131          */
132         public Builder setAttributes(RcsResourceAttributes attributes) {
133             mAttributes = attributes;
134             return this;
135         }
136
137         /**
138          * Register a resource and returns a RCSResourceObject.
139          *
140          * @throws RcsPlatformException
141          *             If registering a resource is failed.
142          *
143          */
144         public RcsResourceObject build() {
145             return nativeBuild(mUri, mType, mInterface, mIsObservable,
146                     mIsDiscovervable, mAttributes);
147         }
148     }
149
150     /**
151      * This provides the way to get the attributes of RcsResourceObject with
152      * lock.
153      * When a thread holds the lock, the other threads will be pending until the
154      * lock is released by unlock.
155      *
156      * Here is the standard idiom for AttributesLock:
157      *
158      * <pre>
159      * {@code
160      * AttributesLock lock = rcsResourceObject.getAttributesLock();
161      *
162      * try {
163      *     lock.lock();
164      *
165      *     ....
166      *
167      *     lock.apply();
168      * } finally {
169      *     lock.unlock();
170      * }
171      * }
172      * </pre>
173      */
174     public static class AttributesLock {
175
176         private final WeakReference<RcsResourceObject> mResourceObjectRef;
177
178         private RcsLockedAttributes mCurrentAttributes;
179
180         private AttributesLock(RcsResourceObject resourceObj) {
181             mResourceObjectRef = new WeakReference<RcsResourceObject>(
182                     resourceObj);
183         }
184
185         private RcsResourceObject ensureResourceObject() throws RcsException {
186             final RcsResourceObject object = mResourceObjectRef.get();
187
188             if (object == null || object.isDestroyed()) {
189                 throw new RcsDestroyedObjectException(
190                         "The object is already destroyed!");
191             }
192
193             return object;
194         }
195
196         /**
197          * Locks the attributes of the RcsResourceObject and returns locked
198          * attributes that can be modified until unlocked.
199          *
200          * @return Locked attributes.
201          *
202          * @throws RcsException
203          *             if the RcsResourceObject is destroyed
204          */
205         public RcsLockedAttributes lock() throws RcsException {
206             return mCurrentAttributes = new RcsLockedAttributes(
207                     ensureResourceObject());
208         }
209
210         /**
211          * Changes the state to unlock of the attributes of the
212          * RcsResourceObject.
213          *
214          */
215         public void unlock() {
216             if (mCurrentAttributes == null) return;
217
218             mCurrentAttributes.setUnlockState();
219             mCurrentAttributes = null;
220         }
221
222         /**
223          * Applies the modified attributes to the RcsResourceObject.
224          *
225          * @throws RcsIllegalStateException
226          *             if not in locked state
227          * @throws RcsPlatformException
228          *             if auto notify failed
229          */
230         public void apply() throws RcsIllegalStateException {
231             if (mCurrentAttributes == null) {
232                 throw new RcsIllegalStateException("it is not locked state.");
233             }
234             mCurrentAttributes.apply();
235         }
236     }
237
238     private static native RcsResourceObject nativeBuild(String uri,
239             String resourceType, String resourceInterface, boolean isObservable,
240             boolean isDiscoverable, RcsResourceAttributes attributes);
241
242     private native void nativeSetAttribute(String key, RcsValue value);
243
244     private native RcsValue nativeGetAttributeValue(String key);
245
246     private native boolean nativeRemoveAttribute(String key);
247
248     private native boolean nativeContainsAttribute(String key);
249
250     private native RcsResourceAttributes nativeGetAttributes();
251
252     private native boolean nativeIsObservable();
253
254     private native boolean nativeIsDiscoverable();
255
256     private native void nativeNotify();
257
258     private native void nativeSetAutoNotifyPolicy(AutoNotifyPolicy policy);
259
260     private native AutoNotifyPolicy nativeGetAutoNotifyPolicy();
261
262     private native void nativeSetSetRequestHandlerPolicy(
263             SetRequestHandlerPolicy policy);
264
265     private native SetRequestHandlerPolicy nativeGetSetRequestHandlerPolicy();
266
267     private native void nativeSetGetRequestHandler(GetRequestHandler handler);
268
269     private native void nativeSetSetRequestHandler(SetRequestHandler handler);
270
271     private native void nativeAddAttributeUpdatedListener(String key,
272             OnAttributeUpdatedListener listener);
273
274     private native boolean nativeRemoveAttributeUpdatedListener(String key);
275
276     private RcsResourceObject() {
277     }
278
279     /**
280      * Represents the policy of AutoNotify function of RCSResourceObject class
281      * In accord with this, observers are notified of attributes that are
282      * changed or updated.
283      *
284      * <p>
285      * Attributes are changed or updated according to execution of some
286      * functions which modify attributes or receipt of set requests.
287      *
288      * @see setAttribute
289      * @see removeAttribute
290      * @see getAttributesLock
291      *
292      */
293     public enum AutoNotifyPolicy {
294         /** Never */
295         NEVER,
296
297         /** Always */
298         ALWAYS,
299
300         /** When attributes are changed */
301         UPDATED
302     }
303
304     /**
305      * Represents the policy of set-request handler.
306      * In accord with this, the RCSResourceObject decides whether a set-request
307      * is
308      * acceptable or not.
309      */
310     public enum SetRequestHandlerPolicy {
311         /**
312          * Requests will be ignored if attributes of the request contain
313          * a new key or a value that has different type from the current
314          * value of the key.
315          */
316         NEVER,
317
318         /**
319          * The attributes of the request will be applied unconditionally
320          * even if there are new name or type conflicts.
321          */
322         ACCEPT
323     }
324
325     /**
326      * Interface definition for a handler to be invoked when a get request is
327      * received.
328      * <p>
329      * The handler will be called first when a get request is received, before
330      * the RCSResourceObject handles.
331      *
332      * @see setGetRequestHandler
333      */
334     public interface GetRequestHandler {
335
336         /**
337          * Called when received a get request from the client.
338          *
339          * @param request
340          *            Request information.
341          * @param attributes
342          *            The attributes of the request.
343          *
344          * @return A response to be sent.
345          *
346          * @see RcsGetResponse
347          */
348         RcsGetResponse onGetRequested(RcsRequest request,
349                 RcsResourceAttributes attributes);
350
351     }
352
353     /**
354      * Interface definition for a handler to be invoked when a set request is
355      * received.
356      * <p>
357      * The handler will be called first when a get request is received, before
358      * the RCSResourceObject handles. If the attributes are modified in the
359      * callback, the modified attributes will be set in the RCSResourceObject if
360      * the request is not ignored.
361      *
362      * @see setGetRequestHandler
363      */
364     public interface SetRequestHandler {
365
366         /**
367          * Called when received a set request from the client.
368          *
369          * @param request
370          *            request information
371          * @param attributes
372          *            the attributes of the request.
373          *            it will be applied to the RcsResourceObject
374          *
375          * @return A response indicating how to handle this request.
376          *
377          * @see RcsSetResponse
378          */
379         RcsSetResponse onSetRequested(RcsRequest request,
380                 RcsResourceAttributes attributes);
381
382     }
383
384     /**
385      * Interface definition for a callback to be invoked when an attribute is
386      * updated.
387      */
388     public interface OnAttributeUpdatedListener {
389
390         /**
391          * Called when an attribute value is updated.
392          *
393          * @param oldValue
394          *            the attribute value before updated
395          * @param newValue
396          *            the current resource attribute value
397          */
398         void onAttributeUpdated(RcsValue oldValue, RcsValue newValue);
399     }
400
401     private void assertAlive() throws RcsException {
402         if (!hasHandle()) {
403             throw new RcsDestroyedObjectException(
404                     "The object is already destroyed!");
405         }
406     }
407
408     /**
409      * Sets a particular attribute value.
410      *
411      * @param key
412      *            key with which the specified value is to be associated
413      * @param value
414      *            value to be associated with the specified key
415      *
416      * @throws RcsDestroyedObjectException
417      *             if the object is destroyed
418      * @throws NullPointerException
419      *             if key or value is null
420      *
421      */
422     public void setAttribute(String key, RcsValue value) throws RcsException {
423         assertAlive();
424
425         if (key == null) throw new NullPointerException("key is null");
426         if (value == null) throw new NullPointerException("value is null");
427
428         nativeSetAttribute(key, value);
429     }
430
431     /**
432      * Returns a copied attribute value associated with the supplied key.
433      *
434      * @param key
435      *            the key whose associated value is to be returned
436      *
437      * @return the value to which the specified key is mapped, or null if no
438      *         attribute for the key
439      *
440      * @throws RcsDestroyedObjectException
441      *             if the object is destroyed
442      * @throws NullPointerException
443      *             if key is null
444      */
445     public RcsValue getAttributeValue(String key) throws RcsException {
446         assertAlive();
447
448         if (key == null) throw new NullPointerException("key is null");
449         return nativeGetAttributeValue(key);
450     }
451
452     /**
453      * Removes the mapping for a key from the attributes if it is present.
454      *
455      * @param key
456      *            key whose mapping is to be removed
457      *
458      * @return true if the key is present and the the value mapped is removed.
459      *
460      * @throws RcsDestroyedObjectException
461      *             if the object is destroyed
462      * @throws NullPointerException
463      *             if key is null
464      */
465     public boolean removeAttribute(String key) throws RcsException {
466         assertAlive();
467
468         if (key == null) throw new NullPointerException("key is null");
469         return nativeRemoveAttribute(key);
470     }
471
472     /**
473      * Returns true if the attributes contains a mapping for the specified key.
474      *
475      * @param key
476      *            key whose presence is to be tested
477      *
478      * @return true if the attributes contains a mapping for the specified key.
479      *
480      * @throws RcsDestroyedObjectException
481      *             if the object is destroyed
482      * @throws NullPointerException
483      *             if key is null
484      */
485     public boolean containsAttribute(String key) throws RcsException {
486         assertAlive();
487
488         if (key == null) throw new NullPointerException("key is null");
489         return nativeContainsAttribute(key);
490     }
491
492     /**
493      * Returns a copied attributes of the RCSResourceObject.
494      * To modify the attributes, use {@link AttributesLock}.
495      *
496      * @throws RcsDestroyedObjectException
497      *             if the object is destroyed
498      *
499      * @see getAttributesLock
500      */
501     public RcsResourceAttributes getAttributes() throws RcsException {
502         assertAlive();
503
504         return nativeGetAttributes();
505     }
506
507     /**
508      * Returns an AttributesLock for this RcsResourceObject.
509      *
510      * @throws RcsDestroyedObjectException
511      *             if the object is destroyed
512      */
513     public AttributesLock getAttributesLock() throws RcsException {
514         assertAlive();
515
516         return new AttributesLock(this);
517     }
518
519     /**
520      * Checks whether the resource is observable or not.
521      *
522      * @throws RcsDestroyedObjectException
523      *             if the object is destroyed
524      */
525     public boolean isObservable() throws RcsException {
526         assertAlive();
527
528         return nativeIsObservable();
529     }
530
531     /**
532      * Checks whether the resource is discoverable or not.
533      *
534      * @throws RcsDestroyedObjectException
535      *             if the object is destroyed
536      */
537     public boolean isDiscoverable() throws RcsException {
538         assertAlive();
539
540         return nativeIsDiscoverable();
541     }
542
543     /**
544      * Sets the get request handler. To remove handler, pass null.
545      *
546      * Default behavior is {@link RcsGetResponse#defaultAction()}.
547      *
548      * @throws RcsDestroyedObjectException
549      *             if the object is destroyed
550      */
551     public void setGetRequestHandler(GetRequestHandler handler)
552             throws RcsException {
553         assertAlive();
554
555         nativeSetGetRequestHandler(handler);
556     }
557
558     /**
559      * Sets the set request handler. To remove handler, pass null.
560      *
561      * Default behavior is {@link RcsSetResponse#defaultAction()}.
562      *
563      * @throws RcsDestroyedObjectException
564      *             if the object is destroyed
565      *
566      */
567     public void setSetRequestHandler(SetRequestHandler handler)
568             throws RcsException {
569         assertAlive();
570
571         nativeSetSetRequestHandler(handler);
572     }
573
574     /**
575      * Adds a listener for a particular attribute updated.
576      *
577      * @param key
578      *            the interested attribute's key
579      * @param listener
580      *            listener to be invoked
581      *
582      * @throws NullPointerException
583      *             if key or listener is null
584      * @throws RcsDestroyedObjectException
585      *             if the object is destroyed
586      */
587     public void addAttributeUpdatedListener(String key,
588             OnAttributeUpdatedListener listener) throws RcsException {
589         assertAlive();
590
591         if (key == null) {
592             throw new NullPointerException("key is null.");
593         }
594         if (listener == null) {
595             throw new NullPointerException("listener is null.");
596         }
597
598         nativeAddAttributeUpdatedListener(key, listener);
599     }
600
601     /**
602      * Removes a listener for a particular attribute updated.
603      *
604      * @param key
605      *            key the key associated with the listener to be removed
606      *
607      * @return true if the listener added with same key exists and is removed.
608      *
609      * @throws RcsDestroyedObjectException
610      *             if the object is destroyed
611      * @throws NullPointerException
612      *             if key is null
613      */
614     public boolean removeAttributeUpdatedListener(String key)
615             throws RcsException {
616         assertAlive();
617
618         if (key == null) throw new NullPointerException("key is null");
619         return nativeRemoveAttributeUpdatedListener(key);
620     }
621
622     /**
623      * Notifies all observers of the current attributes.
624      *
625      * @throws RcsDestroyedObjectException
626      *             if the object is destroyed
627      * @throws RcsPlatformException
628      *             if the operation failed
629      */
630     public void notifyObservers() throws RcsException {
631         assertAlive();
632
633         nativeNotify();
634     }
635
636     /**
637      * Sets auto notify policy
638      *
639      * @param policy
640      *            policy to be set
641      *
642      * @throws RcsDestroyedObjectException
643      *             if the object is destroyed
644      *
645      */
646     public void setAutoNotifyPolicy(AutoNotifyPolicy policy)
647             throws RcsException {
648         assertAlive();
649
650         if (policy == null) throw new NullPointerException("policy is null");
651         nativeSetAutoNotifyPolicy(policy);
652     }
653
654     /**
655      * Returns the current policy
656      *
657      * @throws RcsDestroyedObjectException
658      *             if the object is destroyed
659      *
660      */
661     public AutoNotifyPolicy getAutoNotifyPolicy() throws RcsException {
662         assertAlive();
663
664         return nativeGetAutoNotifyPolicy();
665     }
666
667     /**
668      * Sets the policy for handling a set request.
669      *
670      * @param policy
671      *            policy to be set
672      *
673      * @throws RcsDestroyedObjectException
674      *             if the object is destroyed
675      *
676      */
677     public void setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
678             throws RcsException {
679         assertAlive();
680
681         if (policy == null) throw new NullPointerException("policy is null");
682         nativeSetSetRequestHandlerPolicy(policy);
683     }
684
685     /**
686      * Returns the current policy.
687      *
688      * @throws RcsDestroyedObjectException
689      *             if the object is destroyed
690      */
691     public SetRequestHandlerPolicy getSetRequestHandlerPolicy()
692             throws RcsException {
693         assertAlive();
694
695         return nativeGetSetRequestHandlerPolicy();
696     }
697
698     private boolean isDestroyed() {
699         return !hasHandle();
700     }
701
702     /**
703      * Unregister the resource and reclaims all resources used by this object.
704      * This must be called if the resource is not used any longer.
705      *
706      */
707     public void destroy() {
708         super.dispose();
709     }
710 }