/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.crystallography; import java.beans.XMLDecoder; import java.beans.XMLEncoder; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; import java.util.HashSet; import org.jscience.physics.amount.Amount; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.thoughtworks.xstream.core.util.CompositeClassLoader; /** * CalibrationFactory when we go to e4 like all xxxFactory classes this will become * ICalibrationService and be injected. */ public class CalibrationFactory { private static Logger logger = LoggerFactory.getLogger(CalibrationFactory.class); /** * Reads the calibration standards from disk, creating a new one if required. * * Only if save is called will they be persisted for future use. * * @return CalibrationStandards */ public static CalibrationStandards getCalibrationStandards() { return getCalibrationStandards(false); } private static CalibrationStandards staticInstance; /** * * @param createNew * @return cs */ public static CalibrationStandards getCalibrationStandards(boolean createNew) { if (createNew) { return createCalibrationStandards(); } if (staticInstance==null) { staticInstance = createCalibrationStandards(); //staticInstance.setUnmodifiable(true); } return staticInstance; } /** * Call to save CalibrationStandards to disk * @param cs * @throws Exception */ static void saveCalibrationStandards(CalibrationStandards cs) throws Exception { if (cs == null) return; XMLEncoder encoder = null; try { final File calFile = getCalibrantFile(); calFile.getParentFile().mkdirs(); calFile.createNewFile(); encoder = new XMLEncoder(new FileOutputStream(getCalibrantFile())); encoder.writeObject(cs); encoder.flush(); } finally { if (encoder!=null) encoder.close(); } CalibrationStandards old = staticInstance; staticInstance = cs; if (old!=null && old.getSelectedCalibrant()!=null) { fireCalibrantSelectionListeners(cs, cs.getSelectedCalibrant()); } } static CalibrationStandards readCalibrationStandards() throws Exception { final XMLDecoder decoder = new XMLDecoder(new FileInputStream(getCalibrantFile())); final ClassLoader originalLoader = setCustomClassLoader(); try { final CalibrationStandards cs = (CalibrationStandards) decoder.readObject(); cs.setModifiable(true); return cs; } finally { Thread.currentThread().setContextClassLoader(originalLoader); decoder.close(); } } private static ClassLoader setCustomClassLoader() { final ClassLoader originalLoader = Thread.currentThread().getContextClassLoader(); final CompositeClassLoader customLoader = new CompositeClassLoader(); customLoader.add(CalibrationStandards.class.getClassLoader()); customLoader.add(Amount.class.getClassLoader()); AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { Thread.currentThread().setContextClassLoader(customLoader); return null; } }); return originalLoader; } /** * TODO Best place to keep it? Seems to work when tested. * @return file */ private static File getCalibrantFile() { File dir = new File(new File(System.getProperty("user.home")), ".dawn"); try { dir.mkdirs(); } catch (Throwable ne) { try { logger.error("Cannot store calibration standards!", ne); return File.createTempFile("CalibrationStandards", "xml"); } catch (Throwable neOther) { logger.error("Cannot create files! Dawn will not function correctly. Please contact you support representative.", neOther); return null; } } return new File(dir, "CalibrationStandards.xml"); } private static CalibrationStandards createCalibrationStandards() { final File file = getCalibrantFile(); CalibrationStandards cs = null; if (file.exists()) { try { cs = readCalibrationStandards(); } catch (Exception e) { cs = null; } } if (cs==null || cs.isEmpty() || VersionUtils.isOldVersion(CalibrationStandards.CURRENT_VERSION, cs.getVersion())) { cs = new CalibrationStandards(); cs.setVersion(CalibrationStandards.CURRENT_VERSION); // Versions are so that we can wipe out configurations with new Dawn versions if we have to // TODO consider new file for this instead. cs.setCal2peaks(CalibrationStandards.createDefaultCalibrants()); cs.setSelectedCalibrant("Silicon", false); try { saveCalibrationStandards(cs); } catch (Exception e) { logger.error("Cannot save calibration standards!", e); } return cs; } return cs; } private static Collection<CalibrantSelectedListener> listeners; private static boolean processingListeners = false; /** * * @param calibrant */ static void fireCalibrantSelectionListeners(CalibrationStandards standards, String calibrant) { if (listeners==null) return; if (processingListeners) return; try { processingListeners = true; final CalibrantSelectionEvent evt = new CalibrantSelectionEvent(standards, calibrant); for (CalibrantSelectedListener l : listeners) { try { l.calibrantSelectionChanged(evt); } catch (Throwable ne) { logger.error("Cannot fire calibrant selection changed!", ne); } } } finally { processingListeners = false; } } public static void addCalibrantSelectionListener(CalibrantSelectedListener l) { if (listeners==null) listeners = new HashSet<CalibrantSelectedListener>(7); listeners.add(l); } public static void removeCalibrantSelectionListener(CalibrantSelectedListener l) { if (listeners==null) return; listeners.remove(l); } }