/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * 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.pentaho.di.repository.kdr.delegates.metastore; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.RowMetaAndData; import org.pentaho.di.repository.LongObjectId; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.StringObjectId; import org.pentaho.di.repository.kdr.KettleDatabaseRepository; import org.pentaho.di.repository.kdr.delegates.KettleDatabaseRepositoryMetaStoreDelegate; import org.pentaho.metastore.api.IMetaStore; import org.pentaho.metastore.api.IMetaStoreAttribute; import org.pentaho.metastore.api.IMetaStoreElement; import org.pentaho.metastore.api.IMetaStoreElementType; import org.pentaho.metastore.api.exceptions.MetaStoreDependenciesExistsException; import org.pentaho.metastore.api.exceptions.MetaStoreElementExistException; import org.pentaho.metastore.api.exceptions.MetaStoreElementTypeExistsException; import org.pentaho.metastore.api.exceptions.MetaStoreException; import org.pentaho.metastore.api.exceptions.MetaStoreNamespaceExistsException; import org.pentaho.metastore.api.security.IMetaStoreElementOwner; import org.pentaho.metastore.api.security.MetaStoreElementOwnerType; import org.pentaho.metastore.stores.memory.MemoryMetaStore; import org.pentaho.metastore.stores.memory.MemoryMetaStoreElementOwner; public class KettleDatabaseRepositoryMetaStore extends MemoryMetaStore implements IMetaStore { protected KettleDatabaseRepository repository; private KettleDatabaseRepositoryMetaStoreDelegate delegate; public KettleDatabaseRepositoryMetaStore( KettleDatabaseRepository repository ) { this.repository = repository; delegate = repository.metaStoreDelegate; } // Handle namespaces... @Override public List<String> getNamespaces() throws MetaStoreException { try { List<String> namespaces = new ArrayList<String>(); Collection<RowMetaAndData> namespaceRows = delegate.getNamespaces(); for ( RowMetaAndData namespaceRow : namespaceRows ) { String namespace = namespaceRow.getString( KettleDatabaseRepository.FIELD_NAMESPACE_NAME, null ); if ( !Utils.isEmpty( namespace ) ) { namespaces.add( namespace ); } } return namespaces; } catch ( Exception e ) { throw new MetaStoreException( e ); } } @Override public void createNamespace( String namespace ) throws MetaStoreException, MetaStoreNamespaceExistsException { try { ObjectId namespaceId = delegate.getNamespaceId( namespace ); if ( namespaceId != null ) { throw new MetaStoreNamespaceExistsException( "Namespace with name '" + namespace + "' already exists" ); } // insert namespace into R_NAMESPACE // delegate.insertNamespace( namespace ); repository.commit(); } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( e ); } } @Override public void deleteNamespace( String namespace ) throws MetaStoreException, MetaStoreDependenciesExistsException { try { ObjectId namespaceId = delegate.verifyNamespace( namespace ); List<IMetaStoreElementType> elementTypes = getElementTypes( namespace ); if ( !elementTypes.isEmpty() ) { List<String> dependencies = new ArrayList<String>(); for ( IMetaStoreElementType elementType : elementTypes ) { dependencies.add( elementType.getId() ); } throw new MetaStoreDependenciesExistsException( dependencies, "The namespace to delete, '" + namespace + "' is not empty" ); } // Now delete the namespace // delegate.deleteNamespace( namespaceId ); repository.commit(); } catch ( MetaStoreDependenciesExistsException e ) { throw e; } catch ( MetaStoreException e ) { repository.rollback(); throw e; } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( "Unable to delete namespace '" + namespace + "'", e ); } } @Override public boolean namespaceExists( String namespace ) throws MetaStoreException { try { return delegate.getNamespaceId( namespace ) != null; } catch ( Exception e ) { throw new MetaStoreException( "Unable to verify if namespace '" + namespace + "' exists.", e ); } } // Handle the element types public void createElementType( String namespace, IMetaStoreElementType elementType ) throws MetaStoreException, MetaStoreElementTypeExistsException { try { ObjectId namespaceId = delegate.verifyNamespace( namespace ); // See if the element already exists in this namespace // IMetaStoreElementType existingType = getElementTypeByName( namespace, elementType.getName() ); if ( existingType != null ) { throw new MetaStoreElementTypeExistsException( Arrays.asList( existingType ), "Can not create element type with id '" + elementType.getId() + "' because it already exists" ); } KDBRMetaStoreElementType newElementType = new KDBRMetaStoreElementType( delegate, namespace, namespaceId, elementType.getName(), elementType .getDescription() ); newElementType.save(); elementType.setId( newElementType.getId() ); repository.commit(); } catch ( MetaStoreElementTypeExistsException e ) { throw e; } catch ( MetaStoreException e ) { repository.rollback(); throw e; } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( e ); } } @Override public List<IMetaStoreElementType> getElementTypes( String namespace ) throws MetaStoreException { try { LongObjectId namespaceId = delegate.getNamespaceId( namespace ); if ( namespaceId == null ) { return new ArrayList<IMetaStoreElementType>(); } Collection<RowMetaAndData> elementTypeRows = delegate.getElementTypes( namespaceId ); List<IMetaStoreElementType> list = new ArrayList<IMetaStoreElementType>(); for ( RowMetaAndData elementTypeRow : elementTypeRows ) { KDBRMetaStoreElementType elementType = delegate.parseElementType( namespace, namespaceId, elementTypeRow ); list.add( elementType ); } return list; } catch ( Exception e ) { throw new MetaStoreException( "Unable to get list of element types for namespace '" + namespace + "'", e ); } } @Override public List<String> getElementTypeIds( String namespace ) throws MetaStoreException { List<IMetaStoreElementType> elementTypes = getElementTypes( namespace ); ArrayList<String> ids = new ArrayList<String>(); for ( IMetaStoreElementType elementType : elementTypes ) { ids.add( elementType.getId() ); } return ids; } @Override public IMetaStoreElementType getElementType( String namespace, String elementTypeId ) throws MetaStoreException { try { ObjectId namespaceId = delegate.getNamespaceId( namespace ); if ( namespaceId == null ) { return null; } RowMetaAndData elementTypeRow = delegate.getElementType( new LongObjectId( new StringObjectId( elementTypeId ) ) ); return delegate.parseElementType( namespace, namespaceId, elementTypeRow ); } catch ( Exception e ) { throw new MetaStoreException( "Unable to get element type with id '" + elementTypeId + "' in namespace '" + namespace + "'", e ); } } @Override public IMetaStoreElementType getElementTypeByName( String namespace, String elementTypeName ) throws MetaStoreException { try { LongObjectId namespaceId = delegate.getNamespaceId( namespace ); if ( namespaceId == null ) { return null; } LongObjectId elementTypeId = delegate.getElementTypeId( namespaceId, elementTypeName ); if ( elementTypeId == null ) { return null; } RowMetaAndData elementTypeRow = delegate.getElementType( elementTypeId ); return delegate.parseElementType( namespace, namespaceId, elementTypeRow ); } catch ( Exception e ) { throw new MetaStoreException( "Unable to get element type with name '" + elementTypeName + "' in namespace '" + namespace + "'", e ); } } @Override public void updateElementType( String namespace, IMetaStoreElementType elementType ) throws MetaStoreException { try { ObjectId namespaceId = delegate.verifyNamespace( namespace ); String elementTypeId = elementType.getId(); if ( elementTypeId == null ) { IMetaStoreElementType type = getElementTypeByName( namespace, elementType.getName() ); if ( type != null ) { elementTypeId = type.getId(); } } if ( elementTypeId != null ) { delegate.updateElementType( namespaceId, new LongObjectId( new StringObjectId( elementType.getId() ) ), elementType ); repository.commit(); } else { throw new MetaStoreException( "Unable to update element type: no id was provided and the name '" + elementType.getName() + "' didn't match" ); } } catch ( MetaStoreException e ) { throw e; } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( "Unable to update element type", e ); } } @Override public void deleteElementType( String namespace, IMetaStoreElementType elementType ) throws MetaStoreException, MetaStoreDependenciesExistsException { try { Collection<RowMetaAndData> elementTypeRows = delegate.getElements( new LongObjectId( new StringObjectId( elementType.getId() ) ) ); if ( !elementTypeRows.isEmpty() ) { List<String> dependencies = new ArrayList<String>(); for ( RowMetaAndData elementTypeRow : elementTypeRows ) { Long elementTypeId = elementTypeRow.getInteger( KettleDatabaseRepository.FIELD_ELEMENT_TYPE_ID_ELEMENT_TYPE ); dependencies.add( Long.toString( elementTypeId ) ); } throw new MetaStoreDependenciesExistsException( dependencies, "The namespace to delete, '" + namespace + "' is not empty" ); } delegate.deleteElementType( new LongObjectId( new StringObjectId( elementType.getId() ) ) ); repository.commit(); } catch ( MetaStoreDependenciesExistsException e ) { throw e; } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( e ); } } @Override public List<IMetaStoreElement> getElements( String namespace, IMetaStoreElementType elementType ) throws MetaStoreException { try { IMetaStoreElementType type = getElementTypeByName( namespace, elementType.getName() ); if ( type == null ) { return new ArrayList<IMetaStoreElement>(); } Collection<RowMetaAndData> elementRows = delegate.getElements( new LongObjectId( new StringObjectId( type.getId() ) ) ); List<IMetaStoreElement> elements = new ArrayList<IMetaStoreElement>(); for ( RowMetaAndData elementRow : elementRows ) { IMetaStoreElement element = delegate.parseElement( elementType, elementRow ); elements.add( element ); } return elements; } catch ( Exception e ) { throw new MetaStoreException( "Unable to get list of elements from namespace '" + namespace + "' and for element type '" + elementType.getName() + "'", e ); } } @Override public List<String> getElementIds( String namespace, IMetaStoreElementType elementType ) throws MetaStoreException { List<String> ids = new ArrayList<String>(); List<IMetaStoreElement> elements = getElements( namespace, elementType ); for ( IMetaStoreElement element : elements ) { ids.add( element.getId() ); } return ids; } @Override public IMetaStoreElement getElement( String namespace, IMetaStoreElementType elementType, String elementId ) throws MetaStoreException { try { RowMetaAndData elementRow = delegate.getElement( new LongObjectId( new StringObjectId( elementId ) ) ); if ( elementRow == null ) { return null; } return delegate.parseElement( elementType, elementRow ); } catch ( Exception e ) { throw new MetaStoreException( "Unable to get element", e ); } } @Override public IMetaStoreElement getElementByName( String namespace, IMetaStoreElementType elementType, String name ) throws MetaStoreException { try { LongObjectId namespaceId = delegate.getNamespaceId( namespace ); if ( namespaceId == null ) { return null; } LongObjectId elementTypeId = delegate.getElementTypeId( namespaceId, elementType.getName() ); if ( elementTypeId == null ) { return null; } LongObjectId elementId = delegate.getElementId( elementTypeId, name ); if ( elementId == null ) { return null; } RowMetaAndData elementRow = delegate.getElement( elementId ); if ( elementRow == null ) { return null; } return delegate.parseElement( elementType, elementRow ); } catch ( Exception e ) { throw new MetaStoreException( "Unable to get element by name '" + name + "' from namespace '" + namespace + "'", e ); } } @Override public void createElement( String namespace, IMetaStoreElementType elementType, IMetaStoreElement element ) throws MetaStoreException, MetaStoreElementExistException { try { IMetaStoreElement found = getElementByName( namespace, elementType, element.getName() ); if ( found != null ) { throw new MetaStoreElementExistException( Arrays.asList( found ), "The element with name '" + element.getName() + "' already exists" ); } delegate.insertElement( elementType, element ); repository.commit(); } catch ( MetaStoreElementExistException e ) { throw e; } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( "Unable to create element with name '" + element.getName() + "' of type '" + elementType.getName() + "'", e ); } } @Override public void deleteElement( String namespace, IMetaStoreElementType elementType, String elementId ) throws MetaStoreException { try { IMetaStoreElementType type = getElementTypeByName( namespace, elementType.getName() ); if ( type == null ) { throw new MetaStoreException( "Unable to find element type with name '" + elementType.getName() + "'" ); } delegate.deleteElement( new LongObjectId( new StringObjectId( elementId ) ) ); repository.commit(); } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( "Unable to delete element with id '" + elementId + "' of type '" + elementType.getName() + "'", e ); } } @Override public void updateElement( String namespace, IMetaStoreElementType elementType, String elementId, IMetaStoreElement element ) throws MetaStoreException { try { // This is a delete/insert operation // deleteElement( namespace, elementType, elementId ); createElement( namespace, elementType, element ); repository.commit(); } catch ( Exception e ) { repository.rollback(); throw new MetaStoreException( "Unable to update element with id '" + elementId + "' called '" + element.getName() + "' in type '" + elementType.getName() + "'", e ); } } @Override public IMetaStoreElementType newElementType( String namespace ) throws MetaStoreException { return new KDBRMetaStoreElementType( delegate, namespace, null, null, null ); } @Override public IMetaStoreElement newElement() throws MetaStoreException { return new KDBRMetaStoreElement(); } @Override public IMetaStoreElement newElement( IMetaStoreElementType elementType, String id, Object value ) throws MetaStoreException { return new KDBRMetaStoreElement( delegate, elementType, id, value ); } @Override public IMetaStoreAttribute newAttribute( String id, Object value ) throws MetaStoreException { return new KDBRMetaStoreAttribute( delegate, id, value ); } @Override public IMetaStoreElementOwner newElementOwner( String name, MetaStoreElementOwnerType ownerType ) throws MetaStoreException { return new MemoryMetaStoreElementOwner( name, ownerType ); } @Override public String getName() { return repository.getName(); } @Override public String getDescription() { return repository.getRepositoryMeta().getDescription(); } }