/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.server.shared; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.URL; import java.rmi.RemoteException; import java.util.HashMap; import java.util.Map; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import com.servoy.j2db.IServiceProvider; import com.servoy.j2db.J2DBGlobals; import com.servoy.j2db.LocalActiveSolutionHandler; import com.servoy.j2db.persistence.IServer; import com.servoy.j2db.persistence.RepositoryException; import com.servoy.j2db.persistence.RootObjectMetaData; import com.servoy.j2db.persistence.Solution; import com.servoy.j2db.persistence.SolutionMetaData; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.UIUtils; import com.servoy.j2db.util.UIUtils.ThrowingRunnable; import com.servoy.j2db.util.Utils; /** * Load solutions from local client cache if the active update seq matches * * @author jblok */ public class RemoteActiveSolutionHandler extends LocalActiveSolutionHandler { public static final String SMARTCLIENT_SHARED_SOLUTION_DIR_PROPERTY_NAME = "servoy.client.shared_solution_dir"; //$NON-NLS-1$ private final Map<Integer, Long> loadedActiveSolutionUpdateSequences = new HashMap<Integer, Long>(); //solution_id -> asus public RemoteActiveSolutionHandler(IApplicationServer as, IServiceProvider sp) { super(as, sp); } @Override public Solution[] loadActiveSolutions(final RootObjectMetaData[] solutionDefs) throws RepositoryException, RemoteException { final int[] sol_ids = new int[solutionDefs.length]; for (int i = 0; i < sol_ids.length; i++) { sol_ids[i] = solutionDefs[i].getRootObjectId(); } final Solution[] retval = new Solution[solutionDefs.length]; ThrowingRunnable<RepositoryException, RemoteException> r = new ThrowingRunnable<RepositoryException, RemoteException>() { @Override public void run() { try { long asus[] = getApplicationServer().getActiveRootObjectsLastModified(sol_ids); Map<String, IServer> sps = getRepository().getServerProxies(solutionDefs); for (int i = 0; i < solutionDefs.length; i++) { Solution s = loadCachedSolution(solutionDefs[i], asus[i], sps); if (s == null) { //do full load s = loadSolution(solutionDefs[i]); } if (s != null) { if (s.getRepository() == null) { s.setRepository(getRepository()); // transient } loadedActiveSolutionUpdateSequences.put(new Integer(s.getSolutionID()), new Long(asus[i])); s.setServerProxies(sps); } retval[i] = s; } } catch (RepositoryException eo) { e1 = eo; } catch (RemoteException et) { e2 = et; } } }; UIUtils.runWhileDispatchingEvents(r, getServiceProvider()); return retval; } @Override public IApplicationServer getApplicationServer() { return getServiceProvider().getApplicationServer(); } @Override public Solution[] loadLoginSolutionAndModules(final SolutionMetaData mainSolutionDef) throws RepositoryException, RemoteException { final SolutionMetaData[] loginSolutionDefinitions = getApplicationServer().getLoginSolutionDefinitions(mainSolutionDef); if (loginSolutionDefinitions == null) { throw new RepositoryException("Could not load login solution"); } final Solution[] solutions = new Solution[loginSolutionDefinitions.length]; if (loginSolutionDefinitions.length > 0) { ThrowingRunnable<RepositoryException, RemoteException> r = new ThrowingRunnable<RepositoryException, RemoteException>() { @Override public void run() { try { int[] sol_ids = new int[loginSolutionDefinitions.length]; for (int i = 0; i < sol_ids.length; i++) { sol_ids[i] = loginSolutionDefinitions[i].getRootObjectId(); } long asus[] = getApplicationServer().getActiveRootObjectsLastModified(sol_ids); Map<String, IServer> sps = getRepository().getServerProxies(loginSolutionDefinitions); for (int i = 0; i < loginSolutionDefinitions.length; i++) { Solution s = loadCachedSolution(loginSolutionDefinitions[i], asus[i], sps); if (s == null) { //do full load s = getApplicationServer().getLoginSolution(mainSolutionDef, loginSolutionDefinitions[i]); } if (s != null) { if (s.getRepository() == null) { s.setRepository(getRepository()); // transient } loadedActiveSolutionUpdateSequences.put(new Integer(s.getSolutionID()), new Long(asus[i])); s.setServerProxies(sps); } solutions[i] = s; } } catch (RepositoryException eo) { e1 = eo; } catch (RemoteException et) { e2 = et; } } }; UIUtils.runWhileDispatchingEvents(r, getServiceProvider()); } return solutions; } private Solution loadCachedSolution(RootObjectMetaData solutionDef, long lastModified, Map<String, IServer> serverProxies) { int solID = solutionDef.getRootObjectId(); Solution s = null; //try disk load File file = null; FileInputStream fis = null; BufferedInputStream bis = null; GZIPInputStream zip = null; ObjectInputStream ois = null; try { URL url = getServiceProvider().getServerURL(); String name = (url.getHost() + '_' + url.getPort()) + '_' + solutionDef.getName(); file = new File( getServiceProvider().getSettings().getProperty(SMARTCLIENT_SHARED_SOLUTION_DIR_PROPERTY_NAME, System.getProperty("user.home")), J2DBGlobals.CLIENT_LOCAL_DIR + name + ".solution"); //$NON-NLS-1$ //$NON-NLS-2$ if (file.exists()) { fis = new FileInputStream(file); bis = new BufferedInputStream(fis); zip = new GZIPInputStream(bis); ois = new ObjectInputStream(zip); long stored_asus = ois.readLong(); if (stored_asus == lastModified) { Solution fileSolution = (Solution)ois.readObject(); if (fileSolution.getSolutionID() == solID)//check if same { s = fileSolution; s.setServerProxies(serverProxies); Utils.closeInputStream(ois); if (Debug.tracing()) { Debug.trace("Loaded cached solution from: " + file); } } else { Utils.closeInputStream(ois); file.delete(); if (Debug.tracing()) { Debug.trace("Cached solution from: " + file + " was not valid"); } } } else { Utils.closeInputStream(ois); file.delete(); if (Debug.tracing()) { Debug.trace("Cached solution from: " + file + " was not to old"); } } } } catch (Exception e)//can fail when classes are changed and do not longer match { s = null; Debug.trace(e);//no need to show to user Utils.closeInputStream(ois); Utils.closeInputStream(fis); try { if (file != null) file.delete();//if error happens just delete the file } catch (Exception e1) { Debug.error(e1); } } return s; } @Override public void saveActiveSolution(Solution solution) { URL url = getServiceProvider().getServerURL(); String name = (url.getHost() + '_' + url.getPort()) + '_' + solution.getName(); File hiddendir = new File( getServiceProvider().getSettings().getProperty(SMARTCLIENT_SHARED_SOLUTION_DIR_PROPERTY_NAME, System.getProperty("user.home")), J2DBGlobals.CLIENT_LOCAL_DIR); //$NON-NLS-1$ if (!hiddendir.exists()) hiddendir.mkdirs(); Long asus = loadedActiveSolutionUpdateSequences.get(new Integer(solution.getSolutionID())); File file = new File(hiddendir, name + ".solution"); //$NON-NLS-1$ if (!file.exists() && asus != null && asus.longValue() >= 0) { solution.setServerProxies(null);//clear solution.setRepository(null);//clear FileOutputStream fis = null; try { fis = new FileOutputStream(file); BufferedOutputStream bis = new BufferedOutputStream(fis); GZIPOutputStream zip = new GZIPOutputStream(bis); ObjectOutputStream ois = new ObjectOutputStream(zip); ois.writeLong(asus.longValue()); ois.writeObject(solution); ois.close(); fis = null; if (Debug.tracing()) { Debug.trace("Solution saved to: " + file); } } catch (IOException e) { Debug.error(e); } finally { Utils.closeOutputStream(fis); } } } }