[dsl] Model loading improvements (#1514)

* Model loading improvements

Signed-off-by: Kai Kreuzer <kai@openhab.org>
pull/1521/head
Kai Kreuzer 2020-06-09 09:37:47 +02:00 committed by GitHub
parent 370feb5404
commit e37c28cfc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 57 deletions

View File

@ -98,20 +98,22 @@ public class ModelRepositoryImpl implements ModelRepository {
@Override
public boolean addOrRefreshModel(String name, final InputStream originalInputStream) {
logger.info("Loading model '{}'", name);
Resource resource = null;
InputStream inputStream = null;
try {
if (originalInputStream != null) {
byte[] bytes = originalInputStream.readAllBytes();
String validationResult = validateModel(name, new ByteArrayInputStream(bytes));
if (validationResult != null) {
logger.warn("Configuration model '{}' has errors, therefore ignoring it: {}", name,
validationResult);
removeModel(name);
return false;
}
inputStream = new ByteArrayInputStream(bytes);
byte[] bytes = null;
try (InputStream inputStream = originalInputStream) {
bytes = inputStream.readAllBytes();
String validationResult = validateModel(name, new ByteArrayInputStream(bytes));
if (validationResult != null) {
logger.warn("Configuration model '{}' has errors, therefore ignoring it: {}", name, validationResult);
removeModel(name);
return false;
}
} catch (IOException e) {
logger.warn("Configuration model '{}' cannot be parsed correctly!", name, e);
return false;
}
try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
resource = getResource(name);
if (resource == null) {
synchronized (resourceSet) {
@ -123,13 +125,6 @@ public class ModelRepositoryImpl implements ModelRepository {
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().remove("*");
resource = resourceSet.createResource(URI.createURI(name));
if (resource != null) {
logger.info("Loading model '{}'", 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, resourceOptions);
notifyListeners(name, EventType.ADDED);
return true;
@ -141,12 +136,7 @@ public class ModelRepositoryImpl implements ModelRepository {
} else {
synchronized (resourceSet) {
resource.unload();
logger.info("Refreshing model '{}'", name);
if (inputStream == null) {
resource.load(resourceOptions);
} else {
resource.load(inputStream, resourceOptions);
}
resource.load(inputStream, resourceOptions);
notifyListeners(name, EventType.MODIFIED);
return true;
}
@ -156,13 +146,6 @@ public class ModelRepositoryImpl implements ModelRepository {
if (resource != null) {
resourceSet.getResources().remove(resource);
}
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
return false;
}
@ -189,7 +172,7 @@ public class ModelRepositoryImpl implements ModelRepository {
List<Resource> resourceListCopy = new ArrayList<>(resourceSet.getResources());
return resourceListCopy.stream().filter(input -> {
return input != null && input.getURI().lastSegment().contains(".") && input.isLoaded()
return input.getURI().lastSegment().contains(".") && input.isLoaded()
&& modelType.equalsIgnoreCase(input.getURI().fileExtension());
}).map(from -> {
return from.getURI().path();
@ -203,16 +186,16 @@ public class ModelRepositoryImpl implements ModelRepository {
// Make a copy to avoid ConcurrentModificationException
List<Resource> resourceListCopy = new ArrayList<>(resourceSet.getResources());
for (Resource resource : resourceListCopy) {
if (resource != null && resource.getURI().lastSegment().contains(".") && resource.isLoaded()) {
if (modelType.equalsIgnoreCase(resource.getURI().fileExtension())) {
XtextResource xtextResource = (XtextResource) resource;
// It's not sufficient to discard the derived state.
// The quick & dirts solution is to reparse the whole resource.
// We trigger this by dummy updating the resource.
logger.debug("Refreshing resource '{}'", resource.getURI().lastSegment());
xtextResource.update(1, 0, "");
notifyListeners(resource.getURI().lastSegment(), EventType.MODIFIED);
}
if (resource.getURI().lastSegment().contains(".") && resource.isLoaded()
&& modelType.equalsIgnoreCase(resource.getURI().fileExtension())
&& !resource.getURI().lastSegment().startsWith("tmp_")) {
XtextResource xtextResource = (XtextResource) resource;
// It's not sufficient to discard the derived state.
// The quick & dirts solution is to reparse the whole resource.
// We trigger this by dummy updating the resource.
logger.debug("Refreshing resource '{}'", resource.getURI().lastSegment());
xtextResource.update(1, 0, "");
notifyListeners(resource.getURI().lastSegment(), EventType.MODIFIED);
}
}
}
@ -225,13 +208,13 @@ public class ModelRepositoryImpl implements ModelRepository {
// Make a copy to avoid ConcurrentModificationException
List<Resource> resourceListCopy = new ArrayList<>(resourceSet.getResources());
for (Resource resource : resourceListCopy) {
if (resource != null && resource.getURI().lastSegment().contains(".") && resource.isLoaded()) {
if (modelType.equalsIgnoreCase(resource.getURI().fileExtension())) {
logger.debug("Removing resource '{}'", resource.getURI().lastSegment());
ret.add(resource.getURI().lastSegment());
resourceSet.getResources().remove(resource);
notifyListeners(resource.getURI().lastSegment(), EventType.REMOVED);
}
if (resource.getURI().lastSegment().contains(".") && resource.isLoaded()
&& modelType.equalsIgnoreCase(resource.getURI().fileExtension())
&& !resource.getURI().lastSegment().startsWith("tmp_")) {
logger.debug("Removing resource '{}'", resource.getURI().lastSegment());
ret.add(resource.getURI().lastSegment());
resourceSet.getResources().remove(resource);
notifyListeners(resource.getURI().lastSegment(), EventType.REMOVED);
}
}
}

View File

@ -38,6 +38,8 @@ import org.openhab.core.config.core.ConfigConstants;
import org.openhab.core.model.core.ModelParser;
import org.openhab.core.model.core.ModelRepository;
import org.openhab.core.service.AbstractWatchService;
import org.openhab.core.service.ReadyMarker;
import org.openhab.core.service.ReadyService;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@ -60,6 +62,11 @@ public class FolderObserver extends AbstractWatchService {
/* the model repository is provided as a service */
private final ModelRepository modelRepository;
private static final String READYMARKER_TYPE = "dsl";
private final ReadyService readyService;
private boolean activated;
/* map that stores a list of valid file extensions for each folder */
private final Map<String, String[]> folderFileExtMap = new ConcurrentHashMap<>();
@ -72,18 +79,21 @@ public class FolderObserver extends AbstractWatchService {
private final Map<String, File> nameFileMap = new HashMap<>();
@Activate
public FolderObserver(final @Reference ModelRepository modelRepo) {
public FolderObserver(final @Reference ModelRepository modelRepo, final @Reference ReadyService readyService) {
super(ConfigConstants.getConfigFolder());
this.modelRepository = modelRepo;
this.readyService = readyService;
}
@Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC)
protected void addModelParser(ModelParser modelParser) {
parsers.add(modelParser.getExtension());
// if the component isn't activated yet, ignoredFiles will be empty and thus this method does nothing
processIgnoredFiles(modelParser.getExtension());
if (activated) {
processIgnoredFiles(modelParser.getExtension());
readyService.markReady(new ReadyMarker(READYMARKER_TYPE, modelParser.getExtension()));
}
}
protected void removeModelParser(ModelParser modelParser) {
@ -118,13 +128,14 @@ public class FolderObserver extends AbstractWatchService {
}
addModelsToRepo();
super.activate();
this.activated = true;
}
@Override
@Deactivate
public void deactivate() {
this.activated = false;
super.deactivate();
deleteModelsFromRepo();
this.ignoredFiles.clear();
@ -186,6 +197,9 @@ public class FolderObserver extends AbstractWatchService {
}
}
}
for (String ext : validExtension) {
readyService.markReady(new ReadyMarker(READYMARKER_TYPE, ext));
}
}
}
}

View File

@ -127,7 +127,7 @@ public class GenericItemProvider extends AbstractProvider<Item>
*
* @param factory The {@link ItemFactory} to add.
*/
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
@Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC)
public void addItemFactory(ItemFactory factory) {
itemFactorys.add(factory);
dispatchBindingsPerItemType(null, factory.getSupportedItemTypes());

View File

@ -44,6 +44,7 @@ import org.openhab.core.model.core.ModelParser;
import org.openhab.core.model.core.ModelRepository;
import org.openhab.core.model.core.ModelRepositoryChangeListener;
import org.openhab.core.service.AbstractWatchService;
import org.openhab.core.service.ReadyService;
import org.openhab.core.test.java.JavaOSGiTest;
import org.osgi.service.component.ComponentContext;
@ -89,6 +90,9 @@ public class FolderObserverTest extends JavaOSGiTest {
@Mock
private ModelParser modelParser;
@Mock
private ReadyService readyService;
@Mock
private ComponentContext context;
private Dictionary<String, Object> configProps;
@ -124,7 +128,7 @@ public class FolderObserverTest extends JavaOSGiTest {
modelRepo = new ModelRepoDummy();
folderObserver = new FolderObserver(modelRepo);
folderObserver = new FolderObserver(modelRepo, readyService);
folderObserver.addModelParser(modelParser);
}
@ -348,7 +352,7 @@ public class FolderObserverTest extends JavaOSGiTest {
throw new RuntimeException("intentional failure.");
}
};
FolderObserver localFolderObserver = new FolderObserver(modelRepo);
FolderObserver localFolderObserver = new FolderObserver(modelRepo, readyService);
localFolderObserver.addModelParser(modelParser);
String validExtension = "java";