| /* |
| * Copyright 2015-present Open Networking Laboratory |
| * |
| * 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.onosproject.persistence.impl; |
| |
| import org.apache.felix.scr.annotations.Activate; |
| import org.apache.felix.scr.annotations.Component; |
| import org.apache.felix.scr.annotations.Deactivate; |
| import org.apache.felix.scr.annotations.Service; |
| import org.mapdb.DB; |
| import org.mapdb.DBMaker; |
| import org.onosproject.persistence.PersistenceService; |
| import org.onosproject.persistence.PersistentMapBuilder; |
| import org.onosproject.persistence.PersistentSetBuilder; |
| import org.osgi.service.component.ComponentContext; |
| import org.slf4j.Logger; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Timer; |
| import java.util.TimerTask; |
| |
| import static org.onosproject.security.AppGuard.checkPermission; |
| import static org.onosproject.security.AppPermission.Type.PERSISTENCE_WRITE; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Service that maintains local disk backed maps and sets. This implementation automatically deletes empty structures |
| * on shutdown. |
| */ |
| @Component(immediate = true) |
| @Service |
| public class PersistenceManager implements PersistenceService { |
| |
| private static final String DATABASE_PATH = "localDB"; |
| |
| static final String MAP_PREFIX = "map:"; |
| |
| static final String SET_PREFIX = "set:"; |
| |
| private final Logger log = getLogger(getClass()); |
| |
| private DB localDB = null; |
| |
| private static final int FLUSH_FREQUENCY_MILLIS = 3000; |
| |
| private Timer timer; |
| |
| private final CommitTask commitTask = new CommitTask(); |
| |
| @Activate |
| public void activate(ComponentContext context) { |
| timer = new Timer(); |
| // bundle's persistent storage area directory |
| File dbFolderPath = context.getBundleContext().getDataFile(""); |
| Path dbPath = dbFolderPath.toPath().resolve(DATABASE_PATH); |
| log.debug("dbPath: {}", dbPath); |
| |
| //Make sure the directory exists, if it does not, make it. |
| if (!dbFolderPath.isDirectory()) { |
| log.info("The specified folder location for the database did not exist and will be created."); |
| try { |
| Files.createDirectories(dbFolderPath.toPath()); |
| } catch (IOException e) { |
| log.error("Could not create the required folder for the database."); |
| throw new PersistenceException("Database folder could not be created."); |
| } |
| } |
| //Notify if the database file does not exist. |
| boolean dbFound = Files.exists(dbPath); |
| if (!dbFound) { |
| log.info("The database file could not be located, a new database will be constructed."); |
| |
| } else { |
| log.info("A previous database file has been found."); |
| } |
| localDB = DBMaker.newFileDB(dbPath.toFile()) |
| .asyncWriteEnable() |
| .closeOnJvmShutdown() |
| .make(); |
| timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS); |
| log.info("Started"); |
| } |
| |
| @Deactivate |
| public void deactivate() { |
| timer.cancel(); |
| for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) { |
| String key = entry.getKey(); |
| Object value = entry.getValue(); |
| //This is a map implementation to be handled as such |
| if (value instanceof Map) { |
| Map asMap = (Map) value; |
| if (asMap.isEmpty()) { |
| //the map is empty and may be deleted |
| localDB.delete(key); |
| } |
| //This is a set implementation and can be handled as such |
| } else if (value instanceof Set) { |
| Set asSet = (Set) value; |
| if (asSet.isEmpty()) { |
| //the set is empty and may be deleted |
| localDB.delete(key); |
| } |
| } |
| } |
| localDB.commit(); |
| localDB.close(); |
| log.info("Stopped"); |
| } |
| |
| @Override |
| public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() { |
| checkPermission(PERSISTENCE_WRITE); |
| return new DefaultPersistentMapBuilder<>(localDB); |
| } |
| |
| @Override |
| public <E> PersistentSetBuilder<E> persistentSetBuilder() { |
| checkPermission(PERSISTENCE_WRITE); |
| return new DefaultPersistentSetBuilder<>(localDB); |
| } |
| |
| private class CommitTask extends TimerTask { |
| |
| @Override |
| public void run() { |
| localDB.commit(); |
| } |
| } |
| } |