/* * Copyright 2003-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.generator; import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import org.jetbrains.mps.openapi.model.SModel; import jetbrains.mps.util.FileUtil; import org.jetbrains.annotations.NotNull; import java.io.*; /** * Evgeny Gryaznov, Sep 21, 2010 */ public interface GenerationCacheContainer { ModelCacheContainer getCache(@NotNull SModel descriptor, String hash, boolean create); public interface ModelCacheContainer { @NotNull InputStream openStream(String name) throws IOException; @NotNull OutputStream createStream(String name) throws IOException; void commit(); void revert(); } public static class FileBasedGenerationCacheContainer implements GenerationCacheContainer { private static final Logger LOG = LogManager.getLogger(FileBasedGenerationCacheContainer.class); @NotNull private File myGeneratorCaches; public FileBasedGenerationCacheContainer(@NotNull File generatorCaches) { this.myGeneratorCaches = generatorCaches; } @Override public ModelCacheContainer getCache(@NotNull SModel descriptor, String hash, boolean create) { String modelId = descriptor.getReference().getModelId().toString(); if(modelId == null || modelId.isEmpty()) { LOG.error("bad model id: " + modelId); return null; } modelId = modelId.replaceAll(":", "-"); File modelCacheDir = new File(myGeneratorCaches, modelId); if(!modelCacheDir.exists()) { if(!create) { return null; } if(!modelCacheDir.mkdirs()) { LOG.error("generator cache: cannot create " + modelCacheDir.getAbsolutePath()); return null; } } File hashDir = new File(modelCacheDir, create ? hash + ".gen" : hash); if(!hashDir.exists()) { if(!create) { return null; } if(!hashDir.mkdirs()) { LOG.error("generator cache: cannot create " + hashDir.getAbsolutePath()); return null; } } if(create) { for(File file : hashDir.listFiles()) { file.delete(); } } return new FileBasedModelCacheContainer(modelCacheDir, hashDir, hash, !create); } } public static class FileBasedModelCacheContainer implements ModelCacheContainer { private static final Logger LOG = LogManager.getLogger(FileBasedModelCacheContainer.class); private final File myFolder; private final File myHashDir; private final String myHash; private final boolean myReadOnly; private FileBasedModelCacheContainer(File folder, File hashDir, String hash, boolean readOnly) { myFolder = folder; myHashDir = hashDir; myHash = hash; myReadOnly = readOnly; } @Override @NotNull public InputStream openStream(String name) throws IOException { return new FileInputStream(new File(myHashDir, name)); } @Override @NotNull public OutputStream createStream(String name) throws IOException { if(myReadOnly) { throw new IOException("cannot create stream in read-only cache"); } return new FileOutputStream(new File(myHashDir, name)); } @Override public void commit() { if(myReadOnly) { return; } try { for (File child : myFolder.listFiles()) { if(!myHashDir.getName().equals(child.getName())) { FileUtil.delete(child); } } if(!myHashDir.renameTo(new File(myFolder, myHash))) { LOG.error("cannot rename " + myHashDir.getAbsolutePath() + " to " + myHash); } } catch(SecurityException ex) { LOG.error(ex); } } @Override public void revert() { if(myReadOnly) { return; } try { FileUtil.delete(myHashDir); } catch(SecurityException ex) { LOG.error(ex); } } } }