001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.client;
021 
022 import js.ArrayLike;
023 import js.Id;
024 import js.Initializer;
025 import js.Js;
026 import js.ObjectLike;
027 import js.Value;
028 import js.user.JsHTMLDocument;
029 import jsx.Configurable;
030 import jsx.core.ArrayLikes;
031 import jsx.core.StringLikes;
032 import jsx.core.Variables;
033 
034 /**
035  * <p>A class of cookie objects, with its static methods, providing utilities 
036  * for managing client-side persistence.</p>
037  * 
038  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
039  */
040 public class Cookie extends Configurable
041 {
042     private final static Id<String> NAME = new Id<String>();
043     private final static Id<ObjectLike> CACHE = new Id<ObjectLike>();
044 
045     private Cookie(ObjectLike ini) {
046         super(ini);
047     }
048 
049     /**
050      * <p>Gets the underline cache object from the given cookie.</p>
051      * @param c A cookie object of this class.
052      * @return The actual cache object wrapped by the given cookie object.
053      * @since 1.0
054      */
055     public static ObjectLike getCache(Cookie c) {
056         return ini(c).var(CACHE);
057     }
058 
059     /**
060      * <p>Gets the cookie name from the given cookie object.</p>
061      * @param c A cookie object of this class.
062      * @return The cookie name of the given cookie object.
063      * @since 1.0
064      */
065     public static String getName(Cookie c) {
066         return ini(c).var(NAME);
067     }
068 
069 
070     /**
071      * <p>Creates a cookie object by the cookie name.</p>
072      * @param name The cookie name.
073      * @return The newly created cookie object.
074      * @since 1.0
075      */
076     @SuppressWarnings("unchecked")
077     public static Cookie cache(String name) {
078         String all = JsHTMLDocument.cookie.with(Win.document.var());
079         if (Js.not(all)) {
080             return null;
081         }
082         ArrayLike<String> pairs = (ArrayLike<String>)StringLikes.split(all, ";");
083         String s = Js.add(name, "=");
084         int slen = s.length();
085         String c = null;
086         for (int i = 0, len = ArrayLikes.length(pairs); i < len; i++) {
087             String p = pairs.get(i);
088             if (Js.eq(StringLikes.substring(p, 0, slen), s)) {
089                 c = p;
090                 break;
091             }
092         }
093         if (Js.not(c)) {
094             return null;
095         }
096 
097         ObjectLike cache = new Initializer().var();
098 
099         Cookie cookie = new Cookie(new Initializer().set(
100                 NAME, name
101         ).set(
102                 CACHE, cache
103         ).var());
104 
105         ArrayLike<String> a = (ArrayLike<String>)StringLikes.split(
106                 StringLikes.substring(c, slen), "&"
107         );
108 
109         for (int i = 0, len = ArrayLikes.length(a); i < len; i++) {
110             ArrayLike<String> ap = (ArrayLike<String>)StringLikes.split(a.get(i), ":");
111             cache.var(ap.get(0), Global.decodeURIComponent(ap.get(1)));
112         }
113 
114         return cookie;
115     }
116 
117     /**
118      * <p>Persists a cookie object.</p>
119      * @param cookie The cookie object to persist.
120      * @param sec The <tt>max-age</tt> attribute in seconds of the cookie.
121      * @param path The <tt>path</tt> attribute of the cookie.
122      * @param domain The <tt>domain</tt> attribute of the cookie.
123      * @param secure The <tt>secure</tt> attribute of the cookie.
124      * @since 1.0
125      */
126     public static void store(Cookie cookie, Number sec, String path, String domain, boolean secure) {
127         Value.String v = new Value.String("");
128         ObjectLike cache = getCache(cookie);
129         ArrayLike<String> keys = Js.keys(cache);
130         for (int i = 0, len = ArrayLikes.length(keys); i < len; i++) {
131             if (Js.not(v)) {
132                 v.aadd("&");
133             }
134             String k = keys.get(i);
135             v.aadd(Js.add(Js.add(k, ":"), Global.encodeURIComponent(cache.var(k))));
136         }
137         Value.String c = new Value.String(
138                 cook(getName(cookie), v.var())
139         );
140         if (Variables.defined(sec)) {
141             c.aadd(age(sec));
142         }
143         if (Js.be(path)) {
144             c.aadd(Js.add(";path=", path));
145         }
146         if (Js.be(domain)) {
147             c.aadd(Js.add(";domain=", domain));
148         }
149         if (secure) {
150             c.aadd(";secure");
151         }
152         JsHTMLDocument.cookie.with(
153                 Win.document.var(),
154                 c
155         );
156     }
157 
158     /**
159      * <p>Removes a cookie from the browsers local store.</p>
160      * @param cookie The cookie object to persist.
161      * @param path The <tt>path</tt> attribute of the cookie.
162      * @param domain The <tt>domain</tt> attribute of the cookie.
163      * @param secure The <tt>secure</tt> attribute of the cookie.
164      * @since 1.0
165      */
166     public static void remove(Cookie cookie, String path, String domain, boolean secure) {
167         ini(cookie).var(CACHE, new Initializer().var());
168         store(cookie, 0, path, domain, secure);
169     }
170 
171     private static final String cook(String name, String value) {
172         return Js.add(name, Js.add("=", value));
173     }
174 
175     private static final String age(Number stl) {
176         return Js.add(";max-age=", stl);
177     }
178 
179     private static Boolean isCookieEnabled;
180 
181     /**
182      * <p>Determine whether cookies are enabled.</p>
183      * @return <tt>true</tt> if they appear to be enabled and <tt>false</tt> otherwise.
184      * @since 1.0
185      */
186     public static final boolean isEnabled() {
187         Boolean cookieEnabled = Browser.cookieEnabled.var();
188         if (Variables.defined(cookieEnabled)) {
189             return cookieEnabled;
190         }
191         if (Variables.defined(isCookieEnabled)) {
192             return isCookieEnabled;
193         }
194         String cookie = cook(Cookie.class.getName(), Cookie.class.getName());
195         JsHTMLDocument.cookie.with(
196                 Win.document.var(),
197                 Js.add(cookie, age(9999))
198         );
199         if (JsHTMLDocument.cookie.with(Win.document.var()).indexOf(cookie) == -1) {
200             return isCookieEnabled = false;
201         } else {
202             JsHTMLDocument.cookie.with(
203                     Win.document.var(),
204                     Js.add(cookie, age(0))
205             );
206             return isCookieEnabled = true;
207         }
208     }
209 }