mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 21:31:53 +01:00
Model refactoring, UTF-8 (#1423)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
d8c4ea1c74
commit
b7ab807078
@ -16,6 +16,8 @@ import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The model repository stores the configuration files (EMF models).
|
||||
@ -25,6 +27,7 @@ import org.eclipse.emf.ecore.EObject;
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ModelRepository {
|
||||
|
||||
/**
|
||||
@ -33,7 +36,8 @@ public interface ModelRepository {
|
||||
* @param name name of the requested model
|
||||
* @return the model or null, if not found
|
||||
*/
|
||||
public EObject getModel(String name);
|
||||
@Nullable
|
||||
EObject getModel(String name);
|
||||
|
||||
/**
|
||||
* Adds a model to the repository or refreshes it if it already exists
|
||||
@ -42,7 +46,7 @@ public interface ModelRepository {
|
||||
* @param inputStream an input stream with the model's content, optional if the file already exists
|
||||
* @return true, if it was successfully processed, false otherwise
|
||||
*/
|
||||
public boolean addOrRefreshModel(String name, InputStream inputStream);
|
||||
boolean addOrRefreshModel(String name, InputStream inputStream);
|
||||
|
||||
/**
|
||||
* Removes a model from the repository
|
||||
@ -50,7 +54,7 @@ public interface ModelRepository {
|
||||
* @param name the name of the model to remove
|
||||
* @return true, if model was removed, false, if it did not exist
|
||||
*/
|
||||
public boolean removeModel(String name);
|
||||
boolean removeModel(String name);
|
||||
|
||||
/**
|
||||
* Returns all names of models of a given type (file extension)
|
||||
@ -58,14 +62,14 @@ public interface ModelRepository {
|
||||
* @param modelType the model type to get the names for
|
||||
* @return all names of available models
|
||||
*/
|
||||
public Iterable<String> getAllModelNamesOfType(String modelType);
|
||||
Iterable<String> getAllModelNamesOfType(String modelType);
|
||||
|
||||
/**
|
||||
* Reload and parse all models of the given type
|
||||
*
|
||||
* @param modelType the model type to reload
|
||||
*/
|
||||
public void reloadAllModelsOfType(final String modelType);
|
||||
void reloadAllModelsOfType(final String modelType);
|
||||
|
||||
/**
|
||||
* Remove all models of the given type
|
||||
@ -73,19 +77,19 @@ public interface ModelRepository {
|
||||
* @param modelType the model type to remove
|
||||
* @return all names of the removed models
|
||||
*/
|
||||
public Set<String> removeAllModelsOfType(final String modelType);
|
||||
Set<String> removeAllModelsOfType(final String modelType);
|
||||
|
||||
/**
|
||||
* Adds a change listener
|
||||
*
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addModelRepositoryChangeListener(ModelRepositoryChangeListener listener);
|
||||
void addModelRepositoryChangeListener(ModelRepositoryChangeListener listener);
|
||||
|
||||
/**
|
||||
* Removes a change listener
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeModelRepositoryChangeListener(ModelRepositoryChangeListener listener);
|
||||
void removeModelRepositoryChangeListener(ModelRepositoryChangeListener listener);
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -34,6 +33,8 @@ import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet;
|
||||
import org.eclipse.emf.ecore.util.Diagnostician;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.xtext.resource.SynchronizedXtextResourceSet;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
@ -53,10 +54,13 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Simon Kaufmann - added validation of models before loading them
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
@NonNullByDefault
|
||||
public class ModelRepositoryImpl implements ModelRepository {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ModelRepositoryImpl.class);
|
||||
private final ResourceSet resourceSet;
|
||||
private final Map<String, String> resourceOptions = Collections.singletonMap(XtextResource.OPTION_ENCODING,
|
||||
StandardCharsets.UTF_8.name());
|
||||
|
||||
private final List<ModelRepositoryChangeListener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
@ -74,7 +78,7 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EObject getModel(String name) {
|
||||
public @Nullable EObject getModel(String name) {
|
||||
synchronized (resourceSet) {
|
||||
Resource resource = getResource(name);
|
||||
if (resource != null) {
|
||||
@ -95,8 +99,8 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
@Override
|
||||
public boolean addOrRefreshModel(String name, final InputStream originalInputStream) {
|
||||
Resource resource = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
InputStream inputStream = null;
|
||||
if (originalInputStream != null) {
|
||||
byte[] bytes = originalInputStream.readAllBytes();
|
||||
String validationResult = validateModel(name, new ByteArrayInputStream(bytes));
|
||||
@ -120,15 +124,13 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
resource = resourceSet.createResource(URI.createURI(name));
|
||||
if (resource != null) {
|
||||
logger.info("Loading model '{}'", name);
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put(XtextResource.OPTION_ENCODING, StandardCharsets.UTF_8.name());
|
||||
if (inputStream == null) {
|
||||
logger.warn(
|
||||
"Resource '{}' not found. You have to pass an inputStream to create the resource.",
|
||||
name);
|
||||
return false;
|
||||
}
|
||||
resource.load(inputStream, options);
|
||||
resource.load(inputStream, resourceOptions);
|
||||
notifyListeners(name, EventType.ADDED);
|
||||
return true;
|
||||
} else {
|
||||
@ -140,10 +142,10 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
synchronized (resourceSet) {
|
||||
resource.unload();
|
||||
logger.info("Refreshing model '{}'", name);
|
||||
if (inputStream != null) {
|
||||
resource.load(inputStream, Collections.EMPTY_MAP);
|
||||
if (inputStream == null) {
|
||||
resource.load(resourceOptions);
|
||||
} else {
|
||||
resource.load(Collections.EMPTY_MAP);
|
||||
resource.load(inputStream, resourceOptions);
|
||||
}
|
||||
notifyListeners(name, EventType.MODIFIED);
|
||||
return true;
|
||||
@ -154,6 +156,13 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
if (resource != null) {
|
||||
resourceSet.getResources().remove(resource);
|
||||
}
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -239,7 +248,7 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private Resource getResource(String name) {
|
||||
private @Nullable Resource getResource(String name) {
|
||||
return resourceSet.getResource(URI.createURI(name), false);
|
||||
}
|
||||
|
||||
@ -264,15 +273,15 @@ public class ModelRepositoryImpl implements ModelRepository {
|
||||
* @return error messages as a String if any syntactical error were found, <code>null</code> otherwise
|
||||
* @throws IOException if there was an error with the given {@link InputStream}, loading the resource from there
|
||||
*/
|
||||
private String validateModel(String name, InputStream inputStream) throws IOException {
|
||||
private @Nullable String validateModel(String name, InputStream inputStream) throws IOException {
|
||||
// use another resource for validation in order to keep the original one for emergency-removal in case of errors
|
||||
Resource resource = resourceSet.createResource(URI.createURI("tmp_" + name));
|
||||
try {
|
||||
resource.load(inputStream, Collections.EMPTY_MAP);
|
||||
resource.load(inputStream, resourceOptions);
|
||||
StringBuilder criticalErrors = new StringBuilder();
|
||||
List<String> warnings = new LinkedList<>();
|
||||
|
||||
if (resource != null && !resource.getContents().isEmpty()) {
|
||||
if (!resource.getContents().isEmpty()) {
|
||||
// Check for syntactical errors
|
||||
for (Diagnostic diagnostic : resource.getErrors()) {
|
||||
criticalErrors
|
||||
|
@ -58,12 +58,8 @@ import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
@Component(name = "org.openhab.core.folder", immediate = true, configurationPid = "org.openhab.folder", configurationPolicy = ConfigurationPolicy.REQUIRE)
|
||||
public class FolderObserver extends AbstractWatchService {
|
||||
|
||||
public FolderObserver() {
|
||||
super(ConfigConstants.getConfigFolder());
|
||||
}
|
||||
|
||||
/* the model repository is provided as a service */
|
||||
private ModelRepository modelRepo = null;
|
||||
private final ModelRepository modelRepository;
|
||||
|
||||
/* map that stores a list of valid file extensions for each folder */
|
||||
private final Map<String, String[]> folderFileExtMap = new ConcurrentHashMap<>();
|
||||
@ -75,13 +71,11 @@ public class FolderObserver extends AbstractWatchService {
|
||||
private final Set<File> ignoredFiles = new HashSet<>();
|
||||
private final Map<String, File> nameFileMap = new HashMap<>();
|
||||
|
||||
@Reference
|
||||
public void setModelRepository(ModelRepository modelRepo) {
|
||||
this.modelRepo = modelRepo;
|
||||
}
|
||||
@Activate
|
||||
public FolderObserver(final @Reference ModelRepository modelRepo) {
|
||||
super(ConfigConstants.getConfigFolder());
|
||||
|
||||
public void unsetModelRepository(ModelRepository modelRepo) {
|
||||
this.modelRepo = null;
|
||||
this.modelRepository = modelRepo;
|
||||
}
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC)
|
||||
@ -95,10 +89,8 @@ public class FolderObserver extends AbstractWatchService {
|
||||
protected void removeModelParser(ModelParser modelParser) {
|
||||
parsers.remove(modelParser.getExtension());
|
||||
|
||||
if (modelRepo != null) {
|
||||
Set<String> removed = modelRepo.removeAllModelsOfType(modelParser.getExtension());
|
||||
ignoredFiles.addAll(removed.stream().map(name -> nameFileMap.get(name)).collect(Collectors.toSet()));
|
||||
}
|
||||
Set<String> removed = modelRepository.removeAllModelsOfType(modelParser.getExtension());
|
||||
ignoredFiles.addAll(removed.stream().map(name -> nameFileMap.get(name)).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
@Activate
|
||||
@ -145,7 +137,7 @@ public class FolderObserver extends AbstractWatchService {
|
||||
Set<File> clonedSet = new HashSet<>(this.ignoredFiles);
|
||||
for (File file : clonedSet) {
|
||||
if (extension.equals(getExtension(file.getPath()))) {
|
||||
checkFile(modelRepo, file, ENTRY_CREATE);
|
||||
checkFile(modelRepository, file, ENTRY_CREATE);
|
||||
this.ignoredFiles.remove(file);
|
||||
}
|
||||
}
|
||||
@ -190,7 +182,7 @@ public class FolderObserver extends AbstractWatchService {
|
||||
for (File file : files) {
|
||||
// we omit parsing of hidden files possibly created by editors or operating systems
|
||||
if (!file.isHidden()) {
|
||||
checkFile(modelRepo, file, ENTRY_CREATE);
|
||||
checkFile(modelRepository, file, ENTRY_CREATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,12 +194,10 @@ public class FolderObserver extends AbstractWatchService {
|
||||
private void deleteModelsFromRepo() {
|
||||
Set<String> folders = folderFileExtMap.keySet();
|
||||
for (String folder : folders) {
|
||||
Iterable<String> models = modelRepo.getAllModelNamesOfType(folder);
|
||||
if (models != null) {
|
||||
for (String model : models) {
|
||||
logger.debug("Removing file {} from the model repo.", model);
|
||||
modelRepo.removeModel(model);
|
||||
}
|
||||
Iterable<String> models = modelRepository.getAllModelNamesOfType(folder);
|
||||
for (String model : models) {
|
||||
logger.debug("Removing file {} from the model repo.", model);
|
||||
modelRepository.removeModel(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,21 +219,20 @@ public class FolderObserver extends AbstractWatchService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void checkFile(final ModelRepository modelRepo, final File file, final Kind kind) {
|
||||
if (modelRepo != null && file != null) {
|
||||
private void checkFile(final ModelRepository modelRepository, final File file, final Kind kind) {
|
||||
if (file != null) {
|
||||
try {
|
||||
synchronized (FolderObserver.class) {
|
||||
if ((kind == ENTRY_CREATE || kind == ENTRY_MODIFY)) {
|
||||
if (parsers.contains(getExtension(file.getName()))) {
|
||||
try (InputStream inputStream = Files.newInputStream(file.toPath())) {
|
||||
nameFileMap.put(file.getName(), file);
|
||||
modelRepo.addOrRefreshModel(file.getName(), inputStream);
|
||||
modelRepository.addOrRefreshModel(file.getName(), inputStream);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Error while opening file during update: {}", file.getAbsolutePath());
|
||||
}
|
||||
@ -251,7 +240,7 @@ public class FolderObserver extends AbstractWatchService {
|
||||
ignoredFiles.add(file);
|
||||
}
|
||||
} else if (kind == ENTRY_DELETE) {
|
||||
modelRepo.removeModel(file.getName());
|
||||
modelRepository.removeModel(file.getName());
|
||||
nameFileMap.remove(file.getName());
|
||||
}
|
||||
}
|
||||
@ -306,7 +295,7 @@ public class FolderObserver extends AbstractWatchService {
|
||||
protected void processWatchEvent(WatchEvent<?> event, Kind<?> kind, Path path) {
|
||||
File toCheck = getFileByFileExtMap(folderFileExtMap, path.getFileName().toString());
|
||||
if (toCheck != null && !toCheck.isHidden()) {
|
||||
checkFile(modelRepo, toCheck, kind);
|
||||
checkFile(modelRepository, toCheck, kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -123,8 +124,7 @@ public class FolderObserverTest extends JavaOSGiTest {
|
||||
|
||||
modelRepo = new ModelRepoDummy();
|
||||
|
||||
folderObserver = new FolderObserver();
|
||||
folderObserver.setModelRepository(modelRepo);
|
||||
folderObserver = new FolderObserver(modelRepo);
|
||||
folderObserver.addModelParser(modelParser);
|
||||
}
|
||||
|
||||
@ -348,11 +348,12 @@ public class FolderObserverTest extends JavaOSGiTest {
|
||||
throw new RuntimeException("intentional failure.");
|
||||
}
|
||||
};
|
||||
folderObserver.setModelRepository(modelRepo);
|
||||
FolderObserver localFolderObserver = new FolderObserver(modelRepo);
|
||||
localFolderObserver.addModelParser(modelParser);
|
||||
|
||||
String validExtension = "java";
|
||||
configProps.put(EXISTING_SUBDIR_NAME, "txt,jpg," + validExtension);
|
||||
folderObserver.activate(context);
|
||||
localFolderObserver.activate(context);
|
||||
|
||||
File mockFileWithValidExt = new File(EXISTING_SUBDIR_PATH, "MockFileForModification." + validExtension);
|
||||
mockFileWithValidExt.createNewFile();
|
||||
@ -469,7 +470,7 @@ public class FolderObserverTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EObject getModel(String name) {
|
||||
public @Nullable EObject getModel(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -482,7 +483,7 @@ public class FolderObserverTest extends JavaOSGiTest {
|
||||
|
||||
@Override
|
||||
public Set<String> removeAllModelsOfType(String modelType) {
|
||||
return null;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user