/** * Loads the named objects from a zip file, using the prepared map from names to zip entries. * Returns a map from names to {@link AspectGraph}s. * * @param file the file to read from * @param graphs the mapping from object names to zip entries */ private Map<String, AspectGraph> loadObjects( ResourceKind kind, ZipFile file, Map<String, ZipEntry> graphs) throws IOException { FileType filter = kind.getFileType(); Map<String, AspectGraph> result = new HashMap<String, AspectGraph>(); for (Map.Entry<String, ZipEntry> graphEntry : graphs.entrySet()) { String graphName = filter.stripExtension(graphEntry.getKey()); InputStream in = file.getInputStream(graphEntry.getValue()); try { AttrGraph xmlGraph = GxlIO.instance().loadGraph(in); /* * For backward compatibility, we set the role and name of the * graph. */ xmlGraph.setRole(kind.getGraphRole()); xmlGraph.setName(createQualName(graphName).toString()); addLayout(file, graphEntry.getKey(), xmlGraph); AspectGraph graph = xmlGraph.toAspectGraph(); /* Store the graph */ result.put(graphName, graph); } catch (FormatException exc) { throw new IOException( String.format("Format error while loading '%s':\n%s", graphName, exc.getMessage()), exc); } catch (IOException exc) { throw new IOException( String.format("Error while loading '%s':\n%s", graphName, exc.getMessage()), exc); } } return result; }
/** Saves the content of a given system store to file. */ public static SystemStore save(File file, SystemStore store, boolean clearDir) throws IOException { if (!GRAMMAR.hasExtension(file)) { throw new IOException(String.format("File '%s' does not refer to a production system", file)); } // if the file already exists, rename it // in order to be able to restore if saving fails File newFile = null; if (file.exists()) { newFile = file; do { newFile = new File(newFile.getParent(), "Copy of " + newFile.getName()); } while (newFile.exists()); if (clearDir) { if (!file.renameTo(newFile)) { throw new IOException(String.format("Can't save grammar to existing file '%s'", file)); } } else { Util.copyDirectory(file, newFile, true); } } try { DefaultFileSystemStore result = new DefaultFileSystemStore(file, true); result.reload(); // save properties for (ResourceKind kind : ResourceKind.values()) { if (kind == PROPERTIES) { result.putProperties(store.getProperties()); } else if (kind.isTextBased()) { result.putTexts(kind, store.getTexts(kind)); } else { result.putGraphs(kind, store.getGraphs(kind).values(), false); } } if (newFile != null) { boolean deleted = deleteRecursive(newFile); assert deleted : String.format("Failed to delete '%s'", newFile); } return result; } catch (IOException exc) { file.delete(); // attempt to re-rename previously existing file if (newFile != null) { newFile.renameTo(file); } throw exc; } }
/** Checks if the store is empty. */ public boolean isEmpty() { boolean result = true; for (ResourceKind kind : ResourceKind.values()) { if (kind == PROPERTIES) { result = !this.hasSystemProperties(); } else if (kind.isTextBased()) { result = getTextMap(kind).isEmpty(); } else { result = getGraphMap(kind).isEmpty(); } if (!result) { break; } } return result; }
/** * Loads the named control programs from a zip file, using the prepared map from program names to * zip entries. */ private void loadTexts(ResourceKind kind, ZipFile file, Map<String, ZipEntry> texts) throws IOException { getTextMap(kind).clear(); for (Map.Entry<String, ZipEntry> textEntry : texts.entrySet()) { String controlName = kind.getFileType().stripExtension(textEntry.getKey()); InputStream in = file.getInputStream(textEntry.getValue()); String program = groove.io.Util.readInputStreamToString(in); getTextMap(kind).put(controlName, program); } }
@Override public void reload() throws IOException { ZipFile zipFile; if (this.file == null) { zipFile = ((JarURLConnection) this.url.openConnection()).getJarFile(); } else { zipFile = new ZipFile(this.file); } // collect the relevant entries Map<ResourceKind, Map<String, ZipEntry>> zipEntryMap = new EnumMap<ResourceKind, Map<String, ZipEntry>>(ResourceKind.class); for (ResourceKind kind : ResourceKind.values()) { zipEntryMap.put(kind, new HashMap<String, ZipEntry>()); } ZipEntry properties = null; for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements(); ) { ZipEntry entry = entries.nextElement(); String entryName = entry.getName(); int entryPrefixLength = this.entryName.length() + 1; if (entryName.startsWith(this.entryName) && entryName.length() > entryPrefixLength) { // strip off prefix + 1 to take case of file separator String restName = entryName.substring(entryPrefixLength); // find out the resource kind by testing the extension ResourceKind kind = null; for (ResourceKind tryKind : ResourceKind.values()) { if (restName.endsWith(tryKind.getFileType().getExtension())) { kind = tryKind; break; } } if (kind == PROPERTIES) { String propertiesName = PROPERTIES.getFileType().stripExtension(restName); if (propertiesName.equals(Groove.PROPERTY_NAME)) { // preferably take the one with the default name properties = entry; } else if (properties == null && propertiesName.equals(this.grammarName)) { // otherwise, take the one with the grammar name properties = entry; } } else if (kind == null) { // must be a layout file if (LAYOUT.hasExtension(restName)) { String objectName = LAYOUT.stripExtension(restName); this.layoutEntryMap.put(objectName, entry); } } else { Object oldEntry = zipEntryMap.get(kind).put(restName, entry); assert oldEntry == null : String.format("Duplicate %s name '%s'", kind.getName(), restName); } } } // now process the entries // first load the properties, as they are necessary for loading types loadProperties(zipFile, properties); for (ResourceKind kind : ResourceKind.values()) { if (kind.isTextBased()) { loadTexts(kind, zipFile, zipEntryMap.get(kind)); } else if (kind.isGraphBased()) { loadGraphs(kind, zipFile, zipEntryMap.get(kind)); } } zipFile.close(); notify(EnumSet.allOf(ResourceKind.class)); this.initialised = true; }