/*
* Copyright 2003-2016 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 org.jetbrains.mps.openapi.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.module.SRepository;
import org.jetbrains.mps.openapi.persistence.DataSource;
import org.jetbrains.mps.openapi.persistence.ModelRoot;
/**
* Represents a model. Models are loaded lazily when needed.
*/
public interface SModel {
SRepository getRepository();
/**
* Returns the id of the model valid within the containing module.
*/
@NotNull
SModelId getModelId();
/**
* This is an equivalent to getModelReference().getModelName
* The returned name of the model may include a stereotype, such as 'generator' or 'tests', separated by the '@' character,
* e.g. jetbrains.mps.sample.generator.main@generator
* @deprecated Prefer {@link #getName()} with access to distinct fractions of the name
*/
@Deprecated
String getModelName();
/**
* This is an equivalent to <code>getModelReference().getName()</code>
* @return name of the model in its full glory
*/
@NotNull
SModelName getName();
@NotNull
SModelReference getReference();
ModelRoot getModelRoot();
/**
* Retrieves the owning module
* TODO: fix remove SModule!
*/
SModule getModule();
/**
* Returns a collection of root nodes. Root nodes are all nodes added to model using addRootNode.
* todo VP: should be immutable collection? Currently it isn't.
*/
Iterable<SNode> getRootNodes();
/**
* Instantiates an SNode of the given concept, suitable for use in this model.
*/
SNode createNode(@NotNull SConcept concept);
/**
* Instantiates an SNode of the given concept, suitable for use in this model, optionally specifying an id for the node.
* If no <code>nodeId</code> was supplied, the call is identical to {@link #createNode(org.jetbrains.mps.openapi.language.SConcept)}
*/
SNode createNode(@NotNull SConcept concept, @Nullable SNodeId nodeId);
/**
* Adds the node as a root to this model.
* Each node in the underlying subtree becomes connected to this model and returns it from the getModel() method.
*
* @throws jetbrains.mps.smodel.IllegalModelChangeError
* when invoked on a read-only model or outside of a valid command.
*/
void addRootNode(SNode node);
/**
* Removes the whole subtree from the model.
*
* @throws jetbrains.mps.smodel.IllegalModelChangeError
* when invoked on a read-only model or outside of a valid command.
*/
void removeRootNode(SNode node);
SNode getNode(SNodeId id);
/**
* The data source which this model was loaded from.
*/
@NotNull
DataSource getSource();
/**
* No changes are permitted.
* For read-only models all modification operations always throw {@link jetbrains.mps.smodel.IllegalModelChangeError}.
*/
boolean isReadOnly();
/**
* The model is fully loaded into memory.
*/
boolean isLoaded();
/**
* When owning a read action lock, this method will fully load the model from the storage.
* Does nothing if already loaded.
* The load() method is called automatically on a not-loaded model whenever elements from it are being resolved.
* Problems can be retrieved later by the {@link #getProblems()} method.
*/
void load();
/**
* The list of persistence-specific model problems (like syntax or I/O errors).
* Returns empty list if this model is not loaded yet.
*/
@NotNull
Iterable<Problem> getProblems();
/**
* When owning a write action lock, this method will discard the in-memory representation of the model.
* A modified model is first saved into the storage so that the changes are preserved.
*/
void unload();
void addModelListener(SModelListener l);
void removeModelListener(SModelListener l);
/**
* This method will be removed after 3.3 release.
* @deprecated use {@link #addAccessListener(SNodeAccessListener)}
*/
@Deprecated
void addAccessListener(SModelAccessListener l);
/**
* This method will be removed after 3.3 release.
* @deprecated use {@link #removeAccessListener(SNodeAccessListener)}
*/
@Deprecated
void removeAccessListener(SModelAccessListener l);
/**
* @param l listener to add, tolerates <code>null</code>
* @since 3.3
*/
void addAccessListener(SNodeAccessListener l);
/**
* @param l listener to remove, tolerates <code>null</code>
* @since 3.3
*/
void removeAccessListener(SNodeAccessListener l);
/**
* As {@link org.jetbrains.mps.openapi.model.SNode} API suggests, any model could be modified. However, it's up to model's
* implementation to decide whether to send notifications about changes or not.
* Attaching a change listener to a model doesn't guarantee changes get dispatched to the listener,
* unless it's a model that explicitly states that as part of its contract (e.g. {@link org.jetbrains.mps.openapi.model.EditableSModel}).
*
* Note, there's no guarantee about listener uniqueness, i.e. it's unspecified what happens if the same listener instance is added twice.
*
* @param l listener to add, tolerates <code>null</code>
* @since 3.3
*/
void addChangeListener(SNodeChangeListener l);
/**
* @param l listener to remove, tolerates <code>null</code> and unknown (not registered) listeners
* @since 3.3
*/
void removeChangeListener(SNodeChangeListener l);
/**
* Represents a problem with the persistence.
*/
interface Problem {
enum Kind {
Load,
Save
}
/**
* Returns whether it was a save or load problem. Save problems can arise when an AST content
* doesn't fit into the persistence format.
*/
Kind getKind();
/**
* When line and column are available, returns the location of the stream, where the problem occurred,
* or just plain text description of the location otherwise.
*/
String getLocation();
int getColumn();
int getLine();
String getText();
/**
* Errors usually cause model to be partially loaded, so it cannot be saved back to the storage later.
*/
boolean isError();
/**
* The incomplete node (when available) for load problems, or a node which caused troubles during save operation.
*/
SNode getNode();
}
}