| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.ambari.server.view; |
| |
| import com.google.inject.Binding; |
| import com.google.inject.ConfigurationException; |
| import com.google.inject.Guice; |
| import com.google.inject.Injector; |
| import com.google.inject.persist.Transactional; |
| import org.apache.ambari.server.orm.entities.ViewEntity; |
| import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity; |
| import org.apache.ambari.server.orm.entities.ViewInstanceEntity; |
| import org.apache.ambari.server.view.configuration.EntityConfig; |
| import org.apache.ambari.server.view.configuration.PersistenceConfig; |
| import org.apache.ambari.server.view.persistence.DataStoreImpl; |
| import org.apache.ambari.server.view.persistence.DataStoreModule; |
| import org.apache.ambari.view.DataStore; |
| import org.apache.ambari.view.migration.EntityConverter; |
| import org.apache.ambari.view.PersistenceException; |
| import org.apache.ambari.view.migration.ViewDataMigrationContext; |
| import org.apache.ambari.view.migration.ViewDataMigrationException; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.springframework.beans.BeanUtils; |
| |
| import javax.persistence.EntityManagerFactory; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.UUID; |
| import java.util.WeakHashMap; |
| |
| /** |
| * View data migration context implementation. |
| */ |
| public class ViewDataMigrationContextImpl implements ViewDataMigrationContext { |
| |
| /** |
| * Logger. |
| */ |
| private static final Log LOG = LogFactory.getLog(ViewDataMigrationContextImpl.class); |
| |
| /** |
| * The data store of origin(source) view instance with source data. |
| */ |
| private DataStore originDataStore; |
| |
| /** |
| * The data store of current(target) view instance to store data. |
| */ |
| private DataStore currentDataStore; |
| |
| /** |
| * The origin view instance definition. |
| */ |
| private final ViewInstanceEntity originInstanceDefinition; |
| |
| /** |
| * The current view instance definition. |
| */ |
| private final ViewInstanceEntity currentInstanceDefinition; |
| |
| /** |
| * Constructor. |
| * |
| * @param originInstanceDefinition the origin view instance definition |
| * @param currentInstanceDefinition the current view instance definition |
| */ |
| public ViewDataMigrationContextImpl(ViewInstanceEntity originInstanceDefinition, |
| ViewInstanceEntity currentInstanceDefinition) { |
| this.originInstanceDefinition = originInstanceDefinition; |
| this.currentInstanceDefinition = currentInstanceDefinition; |
| } |
| |
| private Map<ViewInstanceEntity, DataStoreModule> dataStoreModules = new WeakHashMap<>(); |
| |
| /** |
| * Instantiates the data store associated with the instance. |
| * |
| * @param instanceDefinition the view instance definition |
| * @return the data store object associated with view instance |
| */ |
| protected DataStore getDataStore(ViewInstanceEntity instanceDefinition) { |
| if (!dataStoreModules.containsKey(instanceDefinition)) { |
| DataStoreModule module = new DataStoreModule(instanceDefinition,"ambari-view-migration"); |
| dataStoreModules.put(instanceDefinition, module); |
| } |
| Injector injector = Guice.createInjector(dataStoreModules.get(instanceDefinition)); |
| return injector.getInstance(DataStoreImpl.class); |
| } |
| |
| @Override |
| public int getCurrentDataVersion() { |
| return currentInstanceDefinition.getViewEntity().getConfiguration().getDataVersion(); |
| } |
| |
| @Override |
| public int getOriginDataVersion() { |
| return originInstanceDefinition.getViewEntity().getConfiguration().getDataVersion(); |
| } |
| |
| @Override |
| public DataStore getOriginDataStore() { |
| if (originDataStore == null) { |
| originDataStore = getDataStore(originInstanceDefinition); |
| } |
| return originDataStore; |
| } |
| |
| @Override |
| public DataStore getCurrentDataStore() { |
| if (currentDataStore == null) { |
| currentDataStore = getDataStore(currentInstanceDefinition); |
| } |
| return currentDataStore; |
| } |
| |
| @Override |
| @Transactional |
| public void putCurrentInstanceData(String user, String key, String value) { |
| putInstanceData(currentInstanceDefinition, user, key, value); |
| } |
| |
| @Override |
| public void copyAllObjects(Class originEntityClass, Class currentEntityClass) |
| throws ViewDataMigrationException { |
| copyAllObjects(originEntityClass, currentEntityClass, new EntityConverter() { |
| @Override |
| public void convert(Object orig, Object dest) { |
| BeanUtils.copyProperties(orig, dest); |
| } |
| }); |
| } |
| |
| @Override |
| @Transactional |
| public void copyAllObjects(Class originEntityClass, Class currentEntityClass, EntityConverter entityConverter) |
| throws ViewDataMigrationException { |
| try{ |
| for (Object origInstance : getOriginDataStore().findAll(originEntityClass, null)) { |
| Object newInstance = currentEntityClass.newInstance(); |
| entityConverter.convert(origInstance, newInstance); |
| getCurrentDataStore().store(newInstance); |
| } |
| } catch (PersistenceException | InstantiationException | IllegalAccessException e) { |
| String msg = "Error occured during copying data. Persistence entities are not compatible."; |
| LOG.error(msg); |
| throw new ViewDataMigrationException(msg, e); |
| } |
| } |
| |
| @Override |
| public void copyAllInstanceData() { |
| for (Map.Entry<String, Map<String, String>> userData : getOriginInstanceDataByUser().entrySet()) { |
| for (Map.Entry<String, String> entry : userData.getValue().entrySet()) { |
| putCurrentInstanceData(userData.getKey(), entry.getKey(), entry.getValue()); |
| } |
| } |
| } |
| |
| @Override |
| public ViewInstanceEntity getOriginInstanceDefinition() { |
| return originInstanceDefinition; |
| } |
| |
| @Override |
| public Map<String, Class> getOriginEntityClasses() { |
| ViewEntity viewDefinition = originInstanceDefinition.getViewEntity(); |
| return getPersistenceClassesOfView(viewDefinition); |
| } |
| |
| @Override |
| public Map<String, Class> getCurrentEntityClasses() { |
| ViewEntity viewDefinition = currentInstanceDefinition.getViewEntity(); |
| return getPersistenceClassesOfView(viewDefinition); |
| } |
| |
| /** |
| * Get persistence entities of the view instance. |
| * |
| * @param viewDefinition the view definition. |
| * @return the mapping of entity class name to the class objects, |
| * loaded by the classloader of view version. |
| */ |
| private static Map<String, Class> getPersistenceClassesOfView(ViewEntity viewDefinition) { |
| PersistenceConfig persistence = viewDefinition.getConfiguration().getPersistence(); |
| |
| HashMap<String, Class> classes = new HashMap<>(); |
| if (persistence != null) { |
| for (EntityConfig c : persistence.getEntities()) { |
| try { |
| Class entity = viewDefinition.getClassLoader().loadClass(c.getClassName()); |
| classes.put(c.getClassName(), entity); |
| } catch (ClassNotFoundException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| return classes; |
| } |
| |
| @Override |
| public ViewInstanceEntity getCurrentInstanceDefinition() { |
| return currentInstanceDefinition; |
| } |
| |
| @Override |
| public Map<String, Map<String, String>> getOriginInstanceDataByUser() { |
| return getInstanceDataByUser(originInstanceDefinition); |
| } |
| |
| @Override |
| @Transactional |
| public void putOriginInstanceData(String user, String key, String value) { |
| putInstanceData(originInstanceDefinition, user, key, value); |
| } |
| |
| @Override |
| public Map<String, Map<String, String>> getCurrentInstanceDataByUser() { |
| return getInstanceDataByUser(currentInstanceDefinition); |
| } |
| |
| public void closeMigration() { |
| |
| for (DataStoreModule module : dataStoreModules.values()) { |
| module.close(); |
| } |
| |
| dataStoreModules.clear(); |
| } |
| |
| /** |
| * Save an instance data value for the given key owned by given user. |
| * |
| * @param instanceDefinition the view instance definition |
| * @param user the owner of the data value |
| * @param name the name |
| * @param value the value |
| */ |
| private static void putInstanceData(ViewInstanceEntity instanceDefinition, String user, String name, String value) { |
| ViewInstanceDataEntity oldInstanceDataEntity = getInstanceData(instanceDefinition, user, name); |
| if (oldInstanceDataEntity != null) { |
| instanceDefinition.getData().remove(oldInstanceDataEntity); |
| } |
| |
| ViewInstanceDataEntity instanceDataEntity = new ViewInstanceDataEntity(); |
| instanceDataEntity.setViewName(instanceDefinition.getViewName()); |
| instanceDataEntity.setViewInstanceName(instanceDefinition.getName()); |
| instanceDataEntity.setName(name); |
| instanceDataEntity.setUser(user); |
| instanceDataEntity.setValue(value); |
| instanceDataEntity.setViewInstanceEntity(instanceDefinition); |
| |
| instanceDefinition.getData().add(instanceDataEntity); |
| } |
| |
| /** |
| * Get the instance data entity for the given key and user. |
| * |
| * @param user owner of the data |
| * @param key the key |
| * @return the instance data entity associated with the given key and user |
| */ |
| private static ViewInstanceDataEntity getInstanceData(ViewInstanceEntity instanceDefinition, String user, String key) { |
| for (ViewInstanceDataEntity viewInstanceDataEntity : instanceDefinition.getData()) { |
| if (viewInstanceDataEntity.getName().equals(key) && |
| viewInstanceDataEntity.getUser().equals(user)) { |
| return viewInstanceDataEntity; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get the instance data in the mapping of user owning data to the key-value data. |
| * |
| * @param instanceDefinition the view instance definition |
| * @return mapping of the data owner to the instance data entries |
| */ |
| private static Map<String, Map<String, String>> getInstanceDataByUser(ViewInstanceEntity instanceDefinition) { |
| Map<String, Map<String, String>> instanceDataByUser = new HashMap<>(); |
| for (ViewInstanceDataEntity entity : instanceDefinition.getData()) { |
| |
| if (!instanceDataByUser.containsKey(entity.getUser())) { |
| instanceDataByUser.put(entity.getUser(), new HashMap<String, String>()); |
| } |
| instanceDataByUser.get(entity.getUser()).put(entity.getName(), entity.getValue()); |
| } |
| return instanceDataByUser; |
| } |
| } |