package fr.adrienbrault.idea.symfony2plugin.util.service; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; import fr.adrienbrault.idea.symfony2plugin.extension.CompiledServiceBuilderArguments; import fr.adrienbrault.idea.symfony2plugin.extension.CompiledServiceBuilderFactory; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.*; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class ServiceXmlParserFactory { protected static Map<Project, Map<Class, ServiceXmlParserFactory>> instance = new HashMap<>(); protected Project project; protected ServiceParserInterface serviceParserInstance; protected HashMap<String, Long> serviceFiles = new HashMap<>(); private Collection<CompiledServiceBuilderFactory.Builder> extensions = new ArrayList<>(); private static final ExtensionPointName<CompiledServiceBuilderFactory> EXTENSIONS = new ExtensionPointName<>( "fr.adrienbrault.idea.symfony2plugin.extension.CompiledServiceBuilderFactory" ); public ServiceXmlParserFactory(Project project) { this.project = project; } protected boolean isModified(List<File> serviceFiles) { if(this.serviceFiles.size() != serviceFiles.size()) { return true; } for(File serviceFile: serviceFiles) { if(serviceFile.exists()) { if(!this.serviceFiles.containsKey(serviceFile.getAbsolutePath())) { return true; } if(!this.serviceFiles.get(serviceFile.getAbsolutePath()).equals(serviceFile.lastModified())) { return true; } } else { Symfony2ProjectComponent.getLogger().warn("file not found: " + serviceFiles.toString()); } } if(this.extensions.size() > 0) { for (CompiledServiceBuilderFactory.Builder builder : this.extensions) { if(builder.isModified(project)) { return true; } } } return false; } @Nullable synchronized public <T extends ServiceParserInterface> T parser(Class<T> serviceParser) { Symfony2ProjectComponent symfony2ProjectComponent = this.project.getComponent(Symfony2ProjectComponent.class); List<File> settingsServiceFiles = symfony2ProjectComponent.getContainerFiles(); if (this.serviceParserInstance != null && !this.isModified(settingsServiceFiles)) { return (T) this.serviceParserInstance; } try { this.serviceParserInstance = serviceParser.newInstance(); Symfony2ProjectComponent.getLogger().info("new instance: " + serviceParser.getName()); } catch (InstantiationException | IllegalAccessException ignored) { } if (this.serviceParserInstance != null) { // extensions if(this.extensions.size() > 0) { CompiledServiceBuilderArguments args = new CompiledServiceBuilderArguments(project); for (CompiledServiceBuilderFactory.Builder builder : this.extensions) { builder.build(args); } for (InputStream inputStream : args.getStreams()) { this.serviceParserInstance.parser(inputStream); } } this.serviceFiles = new HashMap<>(); for(File settingsServiceFile: settingsServiceFiles) { if(!settingsServiceFile.exists()) { continue; } try { this.serviceParserInstance.parser(new FileInputStream(settingsServiceFile)); } catch (FileNotFoundException e) { continue; } serviceFiles.put(settingsServiceFile.getAbsolutePath(), settingsServiceFile.lastModified()); } } Symfony2ProjectComponent.getLogger().info("update: " + serviceParser.getName()); return (T) this.serviceParserInstance; } public void setCacheInvalid() { this.serviceFiles = new HashMap<>(); } synchronized public static <T extends ServiceParserInterface> T getInstance(Project project, Class<T> serviceParser){ Map<Class, ServiceXmlParserFactory> projectInstance = instance.computeIfAbsent(project, k -> new HashMap<>()); ServiceXmlParserFactory serviceXmlParserFactory = projectInstance.get(serviceParser); if(serviceXmlParserFactory == null) { serviceXmlParserFactory = new ServiceXmlParserFactory(project); // add extension for new instance for (CompiledServiceBuilderFactory ext : EXTENSIONS.getExtensions()) { serviceXmlParserFactory.extensions.add(ext.create()); } projectInstance.put(serviceParser, serviceXmlParserFactory); } return serviceXmlParserFactory.parser(serviceParser); } synchronized public static void cleanInstance(Project project){ if(instance.containsKey(project)) { Symfony2ProjectComponent.getLogger().info("clean ServiceXmlParserFactory for " + project.getName()); instance.remove(project); } } }