/*
* 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.felix.configurator.impl.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.felix.configurator.impl.Util;
import org.apache.felix.configurator.impl.logger.SystemLogger;
import org.osgi.framework.BundleContext;
public class State extends AbstractState implements Serializable {
private static final long serialVersionUID = 1L;
/** Serialization version. */
private static final int VERSION = 1;
private static final String FILE_NAME = "state.ser";
private final Map<Long, Long> bundlesLastModified = new HashMap<>();
private final Map<Long, Long> bundlesConfigAdminBundleId = new HashMap<>();
private final Set<String> environments = new HashSet<>();
private volatile Set<String> initialHashes;
private volatile transient boolean envsChanged = true;
/**
* Serialize the object
* - write version id
* - serialize fields
* @param out Object output stream
* @throws IOException
*/
private void writeObject(final java.io.ObjectOutputStream out)
throws IOException {
out.writeInt(VERSION);
out.writeObject(bundlesLastModified);
out.writeObject(environments);
out.writeObject(initialHashes);
}
/**
* Deserialize the object
* - read version id
* - deserialize fields
*/
@SuppressWarnings("unchecked")
private void readObject(final java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
final int version = in.readInt();
if ( version < 1 || version > VERSION ) {
throw new ClassNotFoundException(this.getClass().getName());
}
Util.setField(this, "bundlesLastModified", in.readObject());
Util.setField(this, "environments", in.readObject());
initialHashes = (Set<String>) in.readObject();
}
public static State createOrReadState(final BundleContext bc) {
final File f = bc.getDataFile(FILE_NAME);
if ( f == null || !f.exists() ) {
return new State();
}
try ( final ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f)) ) {
return (State) ois.readObject();
} catch ( final ClassNotFoundException | IOException e ) {
SystemLogger.error("Unable to read persisted state from " + f, e);
return new State();
}
}
public static void writeState(final BundleContext bc, final State state) {
final File f = bc.getDataFile(FILE_NAME);
if ( f == null ) {
// do nothing, no file system support
return;
}
try ( final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f)) ) {
oos.writeObject(state);
} catch ( final IOException e) {
SystemLogger.error("Unable to persist state to " + f, e);
}
}
public Long getLastModified(final long bundleId) {
return this.bundlesLastModified.get(bundleId);
}
public void setLastModified(final long bundleId, final long lastModified) {
this.bundlesLastModified.put(bundleId, lastModified);
}
public void removeLastModified(final long bundleId) {
this.bundlesLastModified.remove(bundleId);
}
public Long getConfigAdminBundleId(final long bundleId) {
return this.bundlesConfigAdminBundleId.get(bundleId);
}
public void setConfigAdminBundleId(final long bundleId, final long lastModified) {
this.bundlesConfigAdminBundleId.put(bundleId, lastModified);
}
public void removeConfigAdminBundleId(final long bundleId) {
this.bundlesConfigAdminBundleId.remove(bundleId);
}
public Set<Long> getKnownBundleIds() {
return this.bundlesLastModified.keySet();
}
public Set<String> getEnvironments() {
return this.environments;
}
public void changeEnvironments(final Set<String> envs) {
this.envsChanged = this.environments.equals(envs);
this.environments.clear();
this.environments.addAll(envs);
}
public boolean environmentsChanged() {
return this.envsChanged;
}
public Set<String> getInitialHashes() {
return this.initialHashes;
}
public void setInitialHashes(final Set<String> value) {
this.initialHashes = value;
}
/**
* Add all configurations for a pid
* @param pid The pid
* @param configs The list of configurations
*/
public void addAll(final String pid, final ConfigList configs) {
if ( configs != null ) {
ConfigList list = this.getConfigurations().get(pid);
if ( list == null ) {
list = new ConfigList();
this.getConfigurations().put(pid, list);
}
list.addAll(configs);
}
}
/**
* Mark all configurations from that bundle as changed to reprocess them
* @param bundleId The bundle id
*/
public void checkEnvironments(final long bundleId) {
for(final String pid : this.getPids()) {
final ConfigList configList = this.getConfigurations(pid);
for(final Config cfg : configList) {
if ( cfg.getBundleId() == bundleId ) {
configList.setHasChanges(true);
break;
}
}
}
}
@Override
public String toString() {
return "State [bundlesLastModified=" + bundlesLastModified + ", environments=" + environments
+ ", initialHashes=" + initialHashes + "]";
}
}