package org.itsnat.droid.impl.browser;
import org.apache.http.client.CookieStore;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.itsnat.droid.ItsNatDroid;
import org.itsnat.droid.ItsNatDroidBrowser;
import org.itsnat.droid.ItsNatDroidException;
import org.itsnat.droid.PageRequest;
import org.itsnat.droid.impl.ItsNatDroidImpl;
import org.itsnat.droid.impl.browser.serveritsnat.CustomFunction;
import org.itsnat.droid.impl.browser.serveritsnat.ItsNatSessionImpl;
import org.itsnat.droid.impl.util.MapLight;
import org.itsnat.droid.impl.util.NamespaceUtil;
import org.itsnat.droid.impl.util.UniqueIdGenerator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import bsh.EvalError;
import bsh.Interpreter;
/**
* Created by jmarranz on 4/06/14.
*/
public class ItsNatDroidBrowserImpl implements ItsNatDroidBrowser
{
public final static String USER_AGENT = "Apache-HttpClient/UNAVAILABLE (java 1.4) ItsNatDroidBrowser"; // Valor por defecto de DefaultHttpClient sin parámetros en emulador 4.0.3, le añadimos ItsNatDroidBrowser
protected ItsNatDroidImpl parent;
protected RequestPropertyMap requestPropertyMap;
protected HttpParams httpParams;
protected int connectTimeout = 6 * 1000;
protected int readTimeout = 7 * 1000;
protected HttpContext httpContext = new BasicHttpContext(); // Para las cookies del Apache Http Client (ej para las sesiones), la verdad es que no se si es multihilo pero no tengo más remedio
protected Interpreter interp = new Interpreter(); // Global
protected UniqueIdGenerator idGenerator = new UniqueIdGenerator();
protected MapLight<String,ItsNatSessionImpl> sessionList = new MapLight<String, ItsNatSessionImpl>();
protected int maxPagesInSession = 5;
protected boolean sslSelfSignedAllowed = false; // Sólo poner a true en pruebas de desarrollo
protected long fileCacheMaxSize = 1000 * 1024; // 1Mb
protected HttpFileCache httpFileCache = new HttpFileCache(fileCacheMaxSize);
public ItsNatDroidBrowserImpl(ItsNatDroidImpl parent)
{
this.parent = parent;
this.requestPropertyMap = getDefaultRequestPropertyMap();
this.httpParams = getDefaultApacheHttpParams();
// http://stackoverflow.com/questions/3587254/how-do-i-manage-cookies-with-httpclient-in-android-and-or-java
CookieStore cookieStore = new BasicCookieStore();
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); // httpContext tiene que ser global de otra manera las cookies no se retienen
try
{
interp.set(NamespaceUtil.XMLNS_ANDROID_ALIAS, NamespaceUtil.XMLNS_ANDROID);
// interp.setStrictJava(true);
// No definimos aquí set("itsNatDoc",null) o similar para poder definir métodos alert y toast
// porque queda "itsNatDoc" como global y cualquier set() cambia valor global y por tanto ya no es local por Page
// Funciones de utilidad que se reflejarán en los Interpreter hijos, pero así se interpretan una sola vez
StringBuilder code = new StringBuilder();
code.append("import org.itsnat.droid.*;");
code.append("import org.itsnat.droid.event.*;");
code.append("import android.view.*;");
code.append("import android.widget.*;");
code.append("import " + CustomFunction.class.getName() + ";");
code.append("arr(a){return new Object[]{a};}");
code.append("arr(a){return new Object[]{a};}");
code.append("arr(a,b){return new Object[]{a,b};}");
code.append("arr(a,b,c){return new Object[]{a,b,c};}");
code.append("arr(a,b,c,d){return new Object[]{a,b,c,d};}");
interp.eval(code.toString());
}
catch (EvalError ex) { throw new ItsNatDroidException(ex); } // No debería ocurrir
}
private static RequestPropertyMap getDefaultRequestPropertyMap()
{
RequestPropertyMap requestPropertyMap = new RequestPropertyMap();
requestPropertyMap.setProperty("Accept-Encoding", "gzip"); // Si el programador no lo quiere siempre puede hacer removeProperty desde la API pública
return requestPropertyMap;
}
private static HttpParams getDefaultApacheHttpParams()
{
// Configuración necesaria del Apache
// Parámetros copiados de los parámetros por defecto de AndroidHttpClient.newInstance(...)
// podríamos crear un AndroidHttpClient y coger los parámetros pero el problema es que "hay que usarlo".
// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/net/http/AndroidHttpClient.java?av=f
BasicHttpParams httpParams = new BasicHttpParams();
httpParams.setParameter("http.useragent", "Apache-HttpClient/UNAVAILABLE (java 1.4)"); // Emulador 4.0.3 SE CAMBIARÁ más adelante
httpParams.setIntParameter("http.socket.timeout", 60 * 1000);
httpParams.setBooleanParameter("http.connection.stalecheck", false);
httpParams.setIntParameter("http.connection.timeout", 60 * 1000);
httpParams.setBooleanParameter("http.protocol.handle-redirects", false);
httpParams.setIntParameter("http.socket.buffer-size", 8192);
// AHORA cambiamos los que nos interesan para dejarlos por defecto
httpParams.setParameter("http.useragent", USER_AGENT); // Añadimos ItsNatDroidBrowser
return httpParams;
}
public ItsNatDroid getItsNatDroid()
{
return getItsNatDroidImpl();
}
public ItsNatDroidImpl getItsNatDroidImpl()
{
return parent;
}
public ItsNatSessionImpl getItsNatSession(String stdSessionId,String sessionToken,String id)
{
ItsNatSessionImpl session = sessionList.get(stdSessionId);
if (session == null || !session.getToken().equals(sessionToken))
{
// Si el token ha cambiado es que se ha recargado el servidor, hay que tener en cuenta que los ids por ej del cliente
// están basados en un contador en memoria
session = new ItsNatSessionImpl(this,stdSessionId,sessionToken,id);
sessionList.put(stdSessionId,session);
}
return session;
}
public void disposeEmptySessions()
{
for(Iterator<Map.Entry<String,ItsNatSessionImpl>> it = sessionList.getEntryList().iterator(); it.hasNext(); )
{
Map.Entry<String,ItsNatSessionImpl> entry = it.next();
if (entry.getValue().getPageCount() == 0) it.remove();
}
}
public void disposeSessionIfEmpty(ItsNatSessionImpl session)
{
if (session.getPageCount() == 0) sessionList.remove(session.getStandardSessionId());
}
public HttpContext getHttpContext() { return httpContext; }
public RequestPropertyMap getRequestPropertyMap()
{
return requestPropertyMap;
}
@Override
public void addRequestProperty(String name, String value)
{
requestPropertyMap.addProperty(name, value);
}
@Override
public void setRequestProperty(String name, String value)
{
requestPropertyMap.setProperty(name, value);
}
@Override
public boolean removeProperty(String name)
{
return requestPropertyMap.removeProperty(name);
}
@Override
public String getRequestProperty(String name)
{
return requestPropertyMap.getPropertySingle(name);
}
@Override
public Map<String, List<String>> getRequestProperties()
{
return requestPropertyMap.getPropertyUnmodifiableMap();
}
public HttpParams getHttpParams()
{
return httpParams;
}
@Override
public void setConnectTimeout(int timeoutMillis)
{
this.connectTimeout = timeoutMillis;
}
@Override
public int getConnectTimeout()
{
return connectTimeout;
}
@Override
public void setReadTimeout(int timeoutMillis)
{
this.readTimeout = timeoutMillis;
}
@Override
public int getReadTimeout()
{
return readTimeout;
}
@Override
public PageRequest createPageRequest()
{
return createPageRequestImpl();
}
public PageRequestImpl createPageRequestImpl()
{
return new PageRequestImpl(this);
}
public UniqueIdGenerator getUniqueIdGenerator()
{
return idGenerator;
}
public Interpreter getInterpreter()
{
return interp;
}
@Override
public int getMaxPagesInSession()
{
return maxPagesInSession;
}
@Override
public void setMaxPagesInSession(int maxPagesInSession)
{
this.maxPagesInSession = maxPagesInSession;
}
@Override
public boolean isSSLSelfSignedAllowed()
{
return sslSelfSignedAllowed;
}
@Override
public void setSSLSelfSignedAllowed(boolean enable)
{
this.sslSelfSignedAllowed = enable;
}
@Override
public long getFileCacheMaxSize()
{
return fileCacheMaxSize;
}
@Override
public void setFileCacheMaxSize(long size)
{
this.fileCacheMaxSize = size;
this.httpFileCache.setMaxCacheSize(fileCacheMaxSize);
}
public HttpFileCache getHttpFileCache()
{
return httpFileCache;
}
}