/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.views;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.validation.constraints.NotNull;
import org.obiba.magma.Datasource;
import org.obiba.magma.Disposable;
import org.obiba.magma.IncompatibleEntityTypeException;
import org.obiba.magma.Initialisable;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.NoSuchDatasourceException;
import org.obiba.magma.NoSuchValueTableException;
import org.obiba.magma.ValueTable;
import org.obiba.magma.Variable;
import org.obiba.magma.views.support.VariableOperationContext;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import edu.umd.cs.findbugs.annotations.Nullable;
public class DefaultViewManagerImpl implements ViewManager, Initialisable, Disposable {
@NotNull
private final Set<ViewAwareDatasource> viewAwareDatasources = Collections
.synchronizedSet(new HashSet<ViewAwareDatasource>());
@NotNull
private final ViewPersistenceStrategy viewPersistenceStrategy;
public DefaultViewManagerImpl(@NotNull ViewPersistenceStrategy viewPersistenceStrategy) {
this.viewPersistenceStrategy = viewPersistenceStrategy;
}
@Override
public Datasource decorate(@NotNull Datasource datasource) {
Set<View> views = viewPersistenceStrategy.readViews(datasource.getName());
ViewAwareDatasource viewAwareDatasource = new ViewAwareDatasource(datasource, views);
// remove an older viewAware datasource with the same name and possibly different types
unregisterDatasource(datasource.getName());
viewAwareDatasources.add(viewAwareDatasource);
return viewAwareDatasource;
}
@Override
public void release(Datasource datasource) {
if (datasource == null) return;
ViewAwareDatasource viewAwareDatasource = null;
for (ViewAwareDatasource ds : viewAwareDatasources) {
if (ds.getName().equals(datasource.getName())) {
viewAwareDatasource = ds;
break;
}
}
if (viewAwareDatasource != null) {
viewAwareDatasources.remove(viewAwareDatasource);
}
}
@Override
public void addView(@NotNull String datasourceName, @NotNull View view, @Nullable String comment,
@Nullable VariableOperationContext context) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasourceName), "datasourceName cannot be null or empty.");
//noinspection ConstantConditions
Preconditions.checkArgument(view != null, "view cannot be null.");
Preconditions.checkArgument(!Strings.isNullOrEmpty(view.getName()), "view name cannot be null or empty.");
ViewAwareDatasource datasource = getViewAwareDatasource(datasourceName);
// Check that variables have the same entity type as the from table
view.initialise();
validateVariablesEntityType(view);
datasource.addView(view);
try {
viewPersistenceStrategy.writeView(datasource.getName(), view, comment, context);
} catch(RuntimeException e) {
// rollback
datasource.removeView(view.getName());
throw e;
}
}
private void validateVariablesEntityType(ValueTable view) {
for(Variable variable : view.getVariables()) {
if(!view.getEntityType().equals(variable.getEntityType())) {
throw new IncompatibleEntityTypeException(view.getEntityType(), variable.getEntityType());
}
}
}
@Override
public void removeView(@NotNull String datasourceName, @NotNull String viewName) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasourceName), "datasourceName cannot be null or empty.");
Preconditions.checkArgument(!Strings.isNullOrEmpty(viewName), "viewName cannot be null or empty.");
ViewAwareDatasource datasource = getViewAwareDatasource(datasourceName);
View view = datasource.getView(viewName);
datasource.removeView(viewName);
try {
viewPersistenceStrategy.removeView(datasource.getName(), viewName);
} catch(RuntimeException e) {
// rollback
datasource.addView(view);
throw e;
}
}
@Override
public void removeAllViews(@NotNull String datasourceName) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasourceName), "datasourceName cannot be null or empty.");
viewPersistenceStrategy.removeViews(datasourceName);
}
@Override
public void unregisterDatasource(@NotNull String datasourceName) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasourceName), "datasourceName cannot be null or empty.");
try {
ViewAwareDatasource viewAwareDatasource = getViewAwareDatasource(datasourceName);
viewAwareDatasources.remove(viewAwareDatasource);
} catch(NoSuchDatasourceException e) {
}
}
@Override
public boolean hasView(@NotNull String datasourceName, @NotNull String viewName) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasourceName), "datasourceName cannot be null or empty.");
Preconditions.checkArgument(!Strings.isNullOrEmpty(viewName), "viewName cannot be null or empty.");
return getViewAwareDatasource(datasourceName).hasView(viewName);
}
/**
* Return the {@link View} from the datasource with the supplied viewName.
*
* @param datasourceName
* @param viewName
* @return The View retrieved from the specified datasource and view.
* @throws MagmaRuntimeException if the parameters are null or empty
* @throws NoSuchDatasourceException if a Datasource with the supplied datasourceName does not exist
* @throws NoSuchValueTableException if a View with the supplied viewName does not exist in datasourceName
*/
@Override
public View getView(@NotNull String datasourceName, @NotNull String viewName) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasourceName), "datasourceName cannot be null or empty.");
Preconditions.checkArgument(!Strings.isNullOrEmpty(viewName), "viewName cannot be null or empty.");
return getViewAwareDatasource(datasourceName).getView(viewName);
}
@Override
public void addViews(@NotNull String datasource, Set<View> views, @Nullable String comment) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(datasource), "datasource cannot be null or empty.");
viewPersistenceStrategy.writeViews(datasource, views, comment, null);
}
@NotNull
private ViewAwareDatasource getViewAwareDatasource(@NotNull String datasourceName) throws NoSuchDatasourceException {
for(ViewAwareDatasource datasource : viewAwareDatasources) {
if(datasource.getName().equals(datasourceName)) {
return datasource;
}
}
throw new NoSuchDatasourceException(datasourceName);
}
@Override
public void initialise() {
viewPersistenceStrategy.initialise();
}
@Override
public void dispose() {
viewPersistenceStrategy.dispose();
}
}