You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by br...@apache.org on 2013/05/07 12:25:15 UTC
svn commit: r1479841 [2/3] - in /ace/trunk: org.apache.ace.agent.itest/
org.apache.ace.agent.itest/.settings/ org.apache.ace.agent.itest/resources/
org.apache.ace.agent.itest/src/ org.apache.ace.agent.itest/src/org/
org.apache.ace.agent.itest/src/org/a...
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentServiceImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentServiceImpl.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentServiceImpl.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentServiceImpl.java Tue May 7 10:25:13 2013
@@ -0,0 +1,302 @@
+/*
+ * 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.ace.agent.deployment;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.deployment.Deployment;
+import org.apache.ace.deployment.service.DeploymentService;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.log.LogService;
+
+//FIXME This is a of the org.apache.ace.deployment it is private and may be better located here.
+
+/**
+ * Provides an implementation for {@link DeploymentService}.
+ */
+public class DeploymentServiceImpl implements DeploymentService {
+
+ private final String TOPIC_DEPLOYMENTPACKAGE_INSTALL = "org/apache/ace/deployment/INSTALL";
+
+ // injected by dependencymanager
+ protected volatile Deployment m_deployer;
+ protected volatile Identification m_identification;
+ protected volatile Discovery m_discovery;
+ protected volatile LogService m_log;
+ protected volatile EventAdmin m_eventAdmin;
+ protected volatile ConnectionFactory m_connectionFactory;
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#getHighestLocalVersion()
+ */
+ public Version getHighestLocalVersion() {
+ Object[] installedPackages = m_deployer.list();
+ List versions = new ArrayList();
+ for (int i = 0; i < installedPackages.length; i++) {
+ if (m_deployer.getName(installedPackages[i]).equals(m_identification.getID())) {
+ versions.add(m_deployer.getVersion(installedPackages[i]));
+ }
+ }
+ return getHighestVersion(versions);
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#getHighestRemoteVersion()
+ */
+ public Version getHighestRemoteVersion() throws IOException {
+ SortedSet<Version> versions = getRemoteVersions(getURL());
+ return ((versions == null) || versions.isEmpty()) ? null : versions.last();
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#getRemoteVersions()
+ */
+ public SortedSet<Version> getRemoteVersions() throws IOException {
+ return getRemoteVersions(getURL());
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#installVersion(org.osgi.framework.Version, org.osgi.framework.Version)
+ */
+ public void installVersion(Version highestRemoteVersion, Version highestLocalVersion) throws IOException, Exception {
+ InputStream inputStream = null;
+
+ m_log.log(LogService.LOG_INFO, "Installing version: " + highestRemoteVersion);
+
+ try {
+ String version = highestRemoteVersion.toString();
+ URL baseURL = getURL();
+ boolean isFileBasedProtocol = "file".equals(baseURL.getProtocol());
+ if (highestLocalVersion != null && !isFileBasedProtocol) {
+ version += "?current=" + highestLocalVersion.toString();
+ }
+ URL dataURL = new URL(baseURL, version);
+ if (isFileBasedProtocol) {
+ File file = urlToFile(dataURL);
+ inputStream = new FileInputStream(file);
+ }
+ else {
+ inputStream = getContents(dataURL);
+ }
+
+ // Post event for auditlog
+ m_eventAdmin.postEvent(createEvent(version, dataURL));
+
+ m_deployer.install(inputStream);
+ }
+ finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (Exception ex) {
+ // Not much we can do.
+ }
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.ace.deployment.service.DeploymentService#update(org.osgi.framework.Version)
+ */
+ public void update(Version toVersion) throws Exception {
+ installVersion(toVersion, getHighestLocalVersion());
+ }
+
+ /**
+ * @param url
+ * @return
+ * @throws IOException
+ */
+ final SortedSet<Version> getRemoteVersions(URL url) throws IOException {
+ if (url == null) {
+ return null;
+ }
+
+ if ("file".equals(url.getProtocol())) {
+ return getVersionsFromDirectory(url);
+ }
+ else {
+ return getVersionsFromServer(url);
+ }
+ }
+
+ /**
+ * @param version
+ * @param dataURL
+ * @return
+ */
+ private Event createEvent(String version, URL dataURL) {
+ Dictionary properties = new Properties();
+ properties.put("deploymentpackage.url", dataURL.toString());
+ properties.put("deploymentpackage.version", version);
+ Event event = new Event(TOPIC_DEPLOYMENTPACKAGE_INSTALL, properties);
+ return event;
+ }
+
+ /**
+ * @param versions
+ * @return
+ */
+ private Version getHighestVersion(List versions) {
+ Version highestVersion = null;
+ for (Iterator i = versions.iterator(); i.hasNext();) {
+ Version version = (Version) i.next();
+ if (highestVersion == null) {
+ highestVersion = version;
+ }
+ else if (version.compareTo(highestVersion) > 0) {
+ highestVersion = version;
+ }
+ }
+ return highestVersion;
+ }
+
+ /**
+ * @return
+ */
+ private URL getURL() {
+ URL host = m_discovery.discover();
+ if (host == null) {
+ return null;
+ }
+ try {
+ return new URL(host, "deployment/" + m_identification.getID() + "/versions/");
+ }
+ catch (MalformedURLException e) {
+ m_log.log(LogService.LOG_WARNING, "Malformed URL", e);
+ return null;
+ }
+ }
+
+ /**
+ * @param url
+ * @return
+ */
+ private SortedSet<Version> getVersionsFromDirectory(URL url) {
+ File file = urlToFile(url);
+ if (!file.isDirectory()) {
+ return null;
+ }
+
+ final File[] files = file.listFiles();
+ SortedSet<Version> versions = new TreeSet<Version>();
+ for (File f : files) {
+ try {
+ Version version = Version.parseVersion(f.getName());
+ if (version != Version.emptyVersion) {
+ versions.add(version);
+ }
+ }
+ catch (IllegalArgumentException e) {
+ // if the file is not a valid version, we skip it
+ }
+ }
+ return versions;
+ }
+
+ /**
+ * @param url
+ * @return
+ */
+ private SortedSet<Version> getVersionsFromServer(URL url) {
+ BufferedReader bufReader = null;
+ try {
+ bufReader = new BufferedReader(new InputStreamReader(getContents(url)));
+ SortedSet<Version> versions = new TreeSet<Version>();
+
+ String versionString;
+ while ((versionString = bufReader.readLine()) != null) {
+ try {
+ Version version = Version.parseVersion(versionString);
+ if (version != Version.emptyVersion) {
+ versions.add(version);
+ }
+ }
+ catch (IllegalArgumentException iae) {
+ m_log.log(LogService.LOG_WARNING, "Received malformed version, ignoring: " + versionString);
+ }
+ }
+
+ return versions;
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_DEBUG, "I/O error accessing server!", ioe);
+ return null;
+ }
+ finally {
+ if (bufReader != null) {
+ try {
+ bufReader.close();
+ }
+ catch (Exception ex) {
+ // not much we can do
+ }
+ }
+ }
+ }
+
+ /**
+ * @param url
+ * @return
+ */
+ private File urlToFile(URL url) {
+ File file;
+ // See: http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
+ // makes a best effort to convert a file URL to a File
+ try {
+ file = new File(url.toURI());
+ }
+ catch (URISyntaxException e) {
+ file = new File(url.getPath());
+ }
+ return file;
+ }
+
+ /**
+ * @param url the remote URL to connect to, cannot be <code>null</code>.
+ * @return an {@link InputStream} to the remote URL, never <code>null</code>.
+ * @throws IOException in case of I/O problems opening the remote connection.
+ */
+ private InputStream getContents(URL url) throws IOException {
+ URLConnection conn = m_connectionFactory.createConnection(url);
+ return conn.getInputStream();
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTask.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTask.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTask.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTask.java Tue May 7 10:25:13 2013
@@ -0,0 +1,72 @@
+/*
+ * 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.ace.agent.deployment;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.apache.ace.deployment.service.DeploymentService;
+import org.osgi.framework.Version;
+import org.osgi.service.log.LogService;
+
+//FIXME This is a of the org.apache.ace.deployment it is private and may be better located here.
+
+/**
+ * Implementation of the <code>Runnable</code> interface that updates software configurations by using the
+ * <code>DeploymentService</code> to determine the current local version and to actually install new versions.
+ */
+public class DeploymentUpdateTask implements Runnable {
+
+ private volatile DeploymentService m_service;
+ private volatile LogService m_log;
+
+ /**
+ * When run a check is made if a higher version is available on the remote. If so, an attempt is made to install
+ * this new version.
+ */
+ public void run() {
+ try {
+ Version highestLocalVersion = m_service.getHighestLocalVersion();
+ Version highestRemoteVersion = m_service.getHighestRemoteVersion();
+
+ if (highestRemoteVersion == null) {
+ // expected if there's no discovered ps or relay server
+ // ACE-220: lower log level; not of real interest...
+ m_log.log(LogService.LOG_DEBUG, "Highest remote: unknown / Highest local: " + highestLocalVersion);
+ return;
+ }
+ // ACE-220: lower log level; not of real interest...
+ m_log.log(LogService.LOG_DEBUG, "Highest remote: " + highestRemoteVersion + " / Highest local: " + highestLocalVersion);
+
+ if ((highestRemoteVersion != null) && ((highestLocalVersion == null) || (highestRemoteVersion.compareTo(highestLocalVersion) > 0))) {
+ // no local version or local version lower than remote, install the update
+ m_service.installVersion(highestRemoteVersion, highestLocalVersion);
+ }
+ }
+ catch (MalformedURLException e) {
+ m_log.log(LogService.LOG_ERROR, "Error creating endpoint url", e);
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_ERROR, "Error accessing resources", e);
+ }
+ catch (Exception e) {
+ m_log.log(LogService.LOG_ERROR, "Error installing update", e);
+ }
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTaskFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTaskFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTaskFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/deployment/DeploymentUpdateTaskFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,54 @@
+/*
+ * 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.ace.agent.deployment;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.ace.agent.spi.OneComponentFactoryBase;
+import org.apache.ace.deployment.service.DeploymentService;
+import org.apache.ace.scheduler.constants.SchedulerConstants;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Creates a executor whiteboard {@link Runnable} service component with a {@link DeploymentUpdateTask} implementation.
+ *
+ */
+public class DeploymentUpdateTaskFactory extends OneComponentFactoryBase {
+
+ @Override
+ public Component createComponent(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) throws ConfigurationException {
+
+ Properties properties = getAgentproperties(configuration);
+ properties.put(SchedulerConstants.SCHEDULER_NAME_KEY, DeploymentUpdateTask.class.getSimpleName());
+ properties.put(SchedulerConstants.SCHEDULER_DESCRIPTION_KEY, "Task that synchronizes the artifacts (bundles, resources) installed on this target with the server.");
+ properties.put(SchedulerConstants.SCHEDULER_RECIPE, 2000);
+
+ return manager.createComponent()
+ .setInterface(Runnable.class.getName(), properties)
+ .setImplementation(new DeploymentUpdateTask())
+ .add(manager.createServiceDependency().setService(DeploymentService.class, getAgentFilter(configuration, null)).setRequired(true))
+ .add(manager.createServiceDependency().setService(LogService.class).setRequired(false));
+ }
+
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/discovery/PropertyBasedDiscoveryFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/discovery/PropertyBasedDiscoveryFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/discovery/PropertyBasedDiscoveryFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/discovery/PropertyBasedDiscoveryFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,67 @@
+/*
+ * 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.ace.agent.discovery;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.ace.agent.spi.OneComponentFactoryBase;
+import org.apache.ace.discovery.Discovery;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Creates a {@link Discovery} service component with an implementation that returns the configured
+ * <code>identification.property.value</code>
+ *
+ */
+public class PropertyBasedDiscoveryFactory extends OneComponentFactoryBase {
+
+ public static final String DISCOVERY_PROPERTY_VALUE = "serverurl";
+
+ @Override
+ public Component createComponent(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) throws ConfigurationException {
+
+ final String urlStr = (String) configuration.get(DISCOVERY_PROPERTY_VALUE);
+ if (urlStr == null || urlStr.equals("")) {
+ throw new ConfigurationException(DISCOVERY_PROPERTY_VALUE, "Missing a valid discovery value");
+ }
+
+ try {
+ final URL url = new URL(urlStr);
+ Discovery impl = new Discovery() {
+
+ @Override
+ public URL discover() {
+ return url;
+ }
+ };
+
+ return manager.createComponent()
+ .setInterface(Discovery.class.getName(), getAgentproperties(configuration)).setImplementation(impl);
+ }
+ catch (MalformedURLException e) {
+ throw new ConfigurationException(DISCOVERY_PROPERTY_VALUE, "Discovery URL is bad: " + urlStr);
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IdentifierBasedIdentificationFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IdentifierBasedIdentificationFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IdentifierBasedIdentificationFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IdentifierBasedIdentificationFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,52 @@
+/*
+ * 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.ace.agent.identification;
+
+import java.util.Map;
+
+import org.apache.ace.agent.spi.OneComponentFactoryBase;
+import org.apache.ace.identification.Identification;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Creates a {@link Identification} service component with an implementation that returns the configured agent
+ * identifier.
+ *
+ */
+public class IdentifierBasedIdentificationFactory extends OneComponentFactoryBase {
+
+ @Override
+ public Component createComponent(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) {
+
+ final String value = getAgentIdentifier(configuration);
+ Identification impl = new Identification() {
+
+ @Override
+ public String getID() {
+ return value;
+ }
+ };
+
+ return manager.createComponent()
+ .setInterface(Identification.class.getName(), getAgentproperties(configuration)).setImplementation(impl);
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IfconfigIdentification.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IfconfigIdentification.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IfconfigIdentification.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/IfconfigIdentification.java Tue May 7 10:25:13 2013
@@ -0,0 +1,131 @@
+/*
+ * 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.ace.agent.identification;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.ace.identification.Identification;
+import org.osgi.service.log.LogService;
+
+/**
+ * Implementation of the <code>Identification</code> interface which will determine a mac-address based ID which is determined
+ * by running the ifconfig command. The first adapter that has been assigned an ip address is used.
+ *
+ * The identification has been tested on <code>ifconfig 1.42 (2001-04-13)</code> which comes with Debian Linux. Similar
+ * versions of ifconfig are likely to work.
+ */
+public class IfconfigIdentification implements Identification {
+
+ private static final String IFCONFIG_COMMAND = "ifconfig";
+ private static final String MAC_IDENTIFIER = "HWaddr ";
+ private static final String IP_IDENTIFIER = "inet addr";
+
+ private volatile LogService m_log; // injected by dependency manager
+
+ private String m_targetID = null;
+
+ public synchronized String getID() {
+ if (m_targetID == null) {
+ BufferedReader reader = null;
+ try {
+ Process process = Runtime.getRuntime().exec(IFCONFIG_COMMAND);
+ InputStream inputStream = process.getInputStream();
+ reader = new BufferedReader(new InputStreamReader(inputStream));
+ m_targetID = parseIfconfigOutput(reader).toLowerCase();
+ }
+ catch (IOException ioe) {
+ m_log.log(LogService.LOG_WARNING, "Unable to determine ifconfig based mac-address target identification.", ioe);
+ return null;
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (IOException e) {
+ // not much we can do
+ }
+ }
+ }
+ }
+ return m_targetID;
+ }
+
+ /**
+ * Parses the mac address of the first active adapter from the output of the ifconfig command.
+ *
+ * @param ifconfigOutput Reader pointing to the output of the ifconfig command.
+ * @return String containing the mac address or <code>null</code> if no valid mac address could be determined.
+ * @throws java.io.IOException If the specified reader could not be read correctly.
+ */
+ protected String parseIfconfigOutput(BufferedReader ifconfigOutput) throws IOException {
+ // Sample output (the part that matters):
+ // eth0 Link encap:Ethernet HWaddr 00:00:21:CF:76:47
+ // inet addr:192.168.1.65 Bcast:192.168.1.255 Mask:255.255.255.0
+ String previousLine = "";
+ String line;
+ while ((line = ifconfigOutput.readLine()) != null) {
+ if (line.indexOf(IP_IDENTIFIER) != -1) {
+ if (previousLine.indexOf(MAC_IDENTIFIER) != -1) {
+ String macAddress = previousLine.substring(previousLine.lastIndexOf(MAC_IDENTIFIER) + MAC_IDENTIFIER.length(), previousLine.length());
+ macAddress = macAddress.trim();
+ if (isValidMac(macAddress)) {
+ return macAddress;
+ }
+ else {
+ return null;
+ }
+ }
+ }
+ previousLine = line;
+ }
+ return null;
+ }
+
+ /**
+ * Verifies whether a string contains a valid mac addres, a valid mac address consists of
+ * 6 pairs of [A-F,a-f,0-9] separated by ':', e.g. <code>0A:F6:33:19:DE:2A</code>.
+ *
+ * @param mac String containing the possible mac address
+ * @return true If the specified string contains a valid mac address, false otherwise.
+ */
+ protected boolean isValidMac(String mac) {
+ if (mac.length() != 17) {
+ return false;
+ }
+ char[] chars = mac.toCharArray();
+ for (int i = 0; i < chars.length; i++) {
+ char c = chars[i];
+ if (i % 3 == 2) {
+ if (':' != c) {
+ return false;
+ }
+ }
+ else if (!(('0' <= c) && (c <= '9')) &&
+ !(('a' <= c) && (c <= 'f')) &&
+ !(('A' <= c) && (c <= 'F'))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/PropertyBasedIdentificationFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/PropertyBasedIdentificationFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/PropertyBasedIdentificationFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/PropertyBasedIdentificationFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,59 @@
+/*
+ * 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.ace.agent.identification;
+
+import java.util.Map;
+
+import org.apache.ace.agent.spi.OneComponentFactoryBase;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.log.LogService;
+
+/**
+ * Creates a {@link Discovery} service component with an implementation that returns the configured
+ * <code>identification.property.value</code>
+ *
+ */
+public class PropertyBasedIdentificationFactory extends OneComponentFactoryBase {
+
+ public static final String IDENTIFICATION_PROPERTY_VALUE = "identification";
+
+ @Override
+ public Component createComponent(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) throws ConfigurationException {
+
+ final String value = configuration.get(IDENTIFICATION_PROPERTY_VALUE);
+ if (value == null || value.equals("")) {
+ throw new ConfigurationException(IDENTIFICATION_PROPERTY_VALUE, "Missing a valid identification value");
+ }
+ Identification impl = new Identification() {
+
+ @Override
+ public String getID() {
+ return value;
+ }
+ };
+
+ return manager.createComponent()
+ .setInterface(Identification.class.getName(), getAgentproperties(configuration)).setImplementation(impl);
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/ifconfigBasedIdentificationFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/ifconfigBasedIdentificationFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/ifconfigBasedIdentificationFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/identification/ifconfigBasedIdentificationFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,43 @@
+/*
+ * 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.ace.agent.identification;
+
+import java.util.Map;
+
+import org.apache.ace.agent.spi.OneComponentFactoryBase;
+import org.apache.ace.identification.Identification;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Component factory for a {@link Identification} service with a {@link IfconfigIdentification} implementation.
+ *
+ */
+public class ifconfigBasedIdentificationFactory extends OneComponentFactoryBase {
+
+ @Override
+ public Component createComponent(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) {
+
+ Identification impl = new IfconfigIdentification();
+ return manager.createComponent()
+ .setInterface(Identification.class.getName(), getAgentproperties(configuration)).setImplementation(impl);
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/Activator.java Tue May 7 10:25:13 2013
@@ -0,0 +1,67 @@
+/*
+ * 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.ace.agent.impl;
+
+import static org.apache.ace.agent.Constants.FACTORY_PID;
+
+import java.util.Properties;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.log.LogService;
+
+/**
+ * OSGi {@link BundleActivator} for the Apache ACE ManagementAGent.
+ *
+ */
+public class Activator extends DependencyActivatorBase {
+
+ private final BundleActivator[] m_activators = new BundleActivator[] {
+ new org.apache.ace.connectionfactory.impl.Activator(),
+ new org.apache.ace.scheduler.Activator(),
+ new org.apache.ace.consolelogger.Activator(),
+ new org.apache.felix.deploymentadmin.Activator()
+ };
+
+ @Override
+ public void init(BundleContext context, DependencyManager manager) throws Exception {
+
+ Properties properties = new Properties();
+ properties.put(Constants.SERVICE_PID, FACTORY_PID);
+ ManagementAgentFactory factory = new ManagementAgentFactory();
+ manager.add(createComponent()
+ .setInterface(ManagedServiceFactory.class.getName(), properties)
+ .setImplementation(factory)
+ .add(createServiceDependency().setService(LogService.class).setRequired(false)));
+
+ StaticConfigurationHandler handler = new StaticConfigurationHandler();
+ manager.add(createComponent()
+ .setImplementation(handler)
+ .add(createServiceDependency().setService(ManagedServiceFactory.class, "(" + Constants.SERVICE_PID + "=" + FACTORY_PID + ")").setRequired(true))
+ .add(createServiceDependency().setService(LogService.class).setRequired(false)));
+ }
+
+ @Override
+ public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ManagementAgentFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ManagementAgentFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ManagementAgentFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ManagementAgentFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,204 @@
+/*
+ * 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.ace.agent.impl;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.ace.agent.ManagementAgent;
+import org.apache.ace.agent.connection.ConnectionFactoryFactory;
+import org.apache.ace.agent.deployment.DeploymentAdminDeployerFactory;
+import org.apache.ace.agent.deployment.DeploymentCheckTaskFactory;
+import org.apache.ace.agent.deployment.DeploymentServiceFactory;
+import org.apache.ace.agent.deployment.DeploymentUpdateTaskFactory;
+import org.apache.ace.agent.discovery.PropertyBasedDiscoveryFactory;
+import org.apache.ace.agent.identification.IdentifierBasedIdentificationFactory;
+import org.apache.ace.agent.logging.LogFactory;
+import org.apache.ace.agent.logging.LogStoreFactory;
+import org.apache.ace.agent.logging.LogSyncTaskFactory;
+import org.apache.ace.agent.spi.ComponentFactory;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.log.LogService;
+
+/**
+ * Factory that handles configuration of management agents services. For every subsystem a {@link ComponentFactory} is
+ * used to instantiate the actual components. Factories can be specified through configuration using a
+ * <code><subsystem>.factory</code> property.
+ */
+public class ManagementAgentFactory implements ManagedServiceFactory {
+
+ private static final Set<String> DEFAULT_FACTORIES = new HashSet<String>();
+
+ static {
+ DEFAULT_FACTORIES.add(IdentifierBasedIdentificationFactory.class.getName());
+ DEFAULT_FACTORIES.add(PropertyBasedDiscoveryFactory.class.getName());
+ DEFAULT_FACTORIES.add(LogFactory.class.getName());
+ DEFAULT_FACTORIES.add(LogStoreFactory.class.getName());
+ DEFAULT_FACTORIES.add(LogSyncTaskFactory.class.getName());
+ DEFAULT_FACTORIES.add(DeploymentServiceFactory.class.getName());
+ DEFAULT_FACTORIES.add(DeploymentAdminDeployerFactory.class.getName());
+ DEFAULT_FACTORIES.add(DeploymentCheckTaskFactory.class.getName());
+ DEFAULT_FACTORIES.add(DeploymentUpdateTaskFactory.class.getName());
+ DEFAULT_FACTORIES.add(ConnectionFactoryFactory.class.getName());
+ }
+
+ private final Map<String, Set<Component>> m_components = new HashMap<String, Set<Component>>();
+
+ private volatile BundleContext m_context;
+ private volatile DependencyManager m_manager;
+ private volatile LogService m_logService;
+
+ @Override
+ public String getName() {
+ return ManagementAgentFactory.class.getSimpleName();
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public void updated(String pid, Dictionary /* <string, String> */properties) throws ConfigurationException {
+
+ Map<String, String> configuration = getConfigurationMap(properties);
+ String agent = getAgentIdentifier(configuration);
+ m_logService.log(LogService.LOG_DEBUG, "Receiving updated for pid/agent : " + pid + "/" + agent);
+
+ Set<ComponentFactory> componentFactories = getComponentFactories(configuration);
+ Set<Component> components = new HashSet<Component>();
+
+ for (ComponentFactory componentFactory : componentFactories) {
+ components.addAll(componentFactory.createComponents(m_context, m_manager, m_logService, configuration));
+ }
+
+ // This is kind of void but at present the only way for user-space consumers (like itest) to see that we
+ // successfully configured the agent. Could be replaced by events. but this API may prove usefull in future to
+ // expose limited functionality into user-space.
+ Properties agentProperties = new Properties();
+ agentProperties.put("agent", agent);
+ Component agentComponent = m_manager.createComponent()
+ .setInterface(ManagementAgent.class.getName(), agentProperties)
+ .setImplementation(new ManagementAgent() {
+ });
+ components.add(agentComponent);
+
+ synchronized (m_components) {
+ m_components.put(pid, components);
+
+ }
+
+ for (Component component : components) {
+ m_manager.add(component);
+ }
+ }
+
+ @Override
+ public void deleted(String pid) {
+ Set<Component> deleted;
+ synchronized (m_components) {
+ deleted = m_components.remove(pid);
+ }
+ if (deleted != null) {
+ for (Component component : deleted) {
+ m_manager.remove(component);
+ }
+ }
+ }
+
+ private Set<ComponentFactory> getComponentFactories(Map<String, String> configuration) throws ConfigurationException {
+
+ Set<ComponentFactory> componentFactories = new HashSet<ComponentFactory>();
+
+ String factoriesProperty = ((String) configuration.get("factories"));
+ if (factoriesProperty == null || factoriesProperty.equals("")) {
+ for (String componentFactoryName : DEFAULT_FACTORIES) {
+ ComponentFactory componentFactory = getComponentFactory(componentFactoryName);
+ componentFactories.add(componentFactory);
+ }
+ }
+ else {
+ String[] componentFactoryNames = factoriesProperty.split(",");
+ for (String componentFactoryName : componentFactoryNames) {
+ ComponentFactory componentFactory = getComponentFactory(componentFactoryName.trim());
+ componentFactories.add(componentFactory);
+ }
+ }
+ return componentFactories;
+ }
+
+ /**
+ * Converts the configuration dictionary to a Map<String, String>.
+ */
+ @SuppressWarnings("rawtypes")
+ private Map<String, String> getConfigurationMap(Dictionary /* <String, String> */properties) {
+ Map<String, String> configuration = new HashMap<String, String>();
+ Enumeration/* <String> */enumeration = properties.keys();
+ while (enumeration.hasMoreElements()) {
+ Object key = enumeration.nextElement();
+ configuration.put(key.toString(), properties.get(key).toString());
+ }
+ return configuration;
+ }
+
+ /**
+ * Extracts the agent identifier form the configuration.
+ */
+ private String getAgentIdentifier(Map<String, String> configuration) throws ConfigurationException {
+ String agentIdentifier = ((String) configuration.get("agent"));
+ if (agentIdentifier != null) {
+ agentIdentifier = agentIdentifier.trim();
+ }
+ if (agentIdentifier == null || agentIdentifier.equals("")) {
+ throw new ConfigurationException("agent", "Updating an agent requires a valid configuration (empty name)");
+ }
+ return agentIdentifier;
+ }
+
+ /**
+ * Returns a factory based on the specified FQN.
+ */
+ private ComponentFactory getComponentFactory(String componentFactoryName) throws ConfigurationException {
+
+ try {
+ Class<?> clazz = ManagementAgentFactory.class.getClassLoader().loadClass(componentFactoryName);
+ if (!ComponentFactory.class.isAssignableFrom(clazz)) {
+ throw new ConfigurationException("factories", "Factory class does not implement ComponentFactory interface: " + componentFactoryName);
+ }
+ try {
+ Object instance = clazz.newInstance();
+ return (ComponentFactory) instance;
+ }
+ catch (InstantiationException e) {
+ throw new ConfigurationException("factories", "Factory class does not have a default constructor: " + componentFactoryName);
+ }
+ catch (IllegalAccessException e) {
+ throw new ConfigurationException("factories", "Factory class does not have a default constructor: " + componentFactoryName);
+ }
+ }
+ catch (ClassNotFoundException e) {
+ throw new ConfigurationException("factories", "Factory class not found: " + componentFactoryName);
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/StaticConfigurationHandler.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/StaticConfigurationHandler.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/StaticConfigurationHandler.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/StaticConfigurationHandler.java Tue May 7 10:25:13 2013
@@ -0,0 +1,232 @@
+/*
+ * 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.ace.agent.impl;
+
+import static org.apache.ace.agent.Constants.FACTORY_PID;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Set;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.log.LogService;
+
+/**
+ * Configuration component that reads a management agent properties file and calls
+ * {@link ManagementAgentFactory#updated(String, Dictionary)} for every agent configuration.
+ *
+ */
+@SuppressWarnings("restriction")
+public class StaticConfigurationHandler {
+
+ private static final Set<String> DEFAULT_ACTIVATORS = new HashSet<String>();
+
+ static {
+ DEFAULT_ACTIVATORS.add(org.apache.ace.connectionfactory.impl.Activator.class.getName());
+ DEFAULT_ACTIVATORS.add(org.apache.ace.scheduler.Activator.class.getName());
+ DEFAULT_ACTIVATORS.add(org.apache.felix.deploymentadmin.Activator.class.getName());
+ }
+
+ private final Set<BundleActivator> m_activators = new HashSet<BundleActivator>();
+
+ // injected services
+ private volatile BundleContext m_context;
+ private volatile ManagedServiceFactory m_agentFactory;
+ private volatile LogService m_logService;
+
+ // lifecycle callback
+ public void start() throws Exception {
+ loadStaticConfiguration();
+ }
+
+ // lifecycle callback
+ public void stop() throws Exception {
+ for (BundleActivator activator : m_activators) {
+ try {
+ activator.stop(m_context);
+ }
+ catch (Exception e) {
+ m_logService.log(LogService.LOG_WARNING, "Activator stop exception", e);
+ }
+ }
+ m_activators.clear();
+ }
+
+ /**
+ * Load static configuration that may hold multiple agents.
+ *
+ */
+ @SuppressWarnings({ "rawtypes" })
+ private void loadStaticConfiguration() throws Exception {
+
+ Dictionary configuration = null;
+
+ String staticConfigurationFile = System.getProperty(FACTORY_PID);
+ if (staticConfigurationFile != null) {
+ configuration = loadProperties(new File(staticConfigurationFile));
+ }
+ if (configuration == null) {
+ configuration = new Hashtable();
+ }
+
+ startActivators(configuration);
+ configureAgents(configuration);
+ }
+
+ private void configureAgents(@SuppressWarnings("rawtypes") Dictionary configuration) throws Exception {
+
+ String agentsProperty = (String) configuration.get("agents");
+ if (agentsProperty == null || agentsProperty.equals("")) {
+ m_logService.log(LogService.LOG_WARNING, "Configuration does not specify any agents");
+ return;
+ }
+
+ String[] agents = agentsProperty.split(",");
+ for (String agent : agents) {
+ @SuppressWarnings("rawtypes")
+ Dictionary dictionary = getAgentConfiguration(agent, configuration);
+ m_agentFactory.updated("static-" + agent, dictionary);
+ }
+ }
+
+ private void startActivators(@SuppressWarnings("rawtypes") Dictionary configuration) throws Exception {
+
+ Set<String> bundleActivators = null;
+ String activatorsProperty = (String) configuration.get("activators");
+ if (activatorsProperty == null || activatorsProperty.equals("")) {
+ bundleActivators = DEFAULT_ACTIVATORS;
+ }
+ else {
+ bundleActivators = new HashSet<String>();
+ String[] activators = activatorsProperty.split(",");
+ for (String activator : activators) {
+ bundleActivators.add(activator.trim());
+ }
+ }
+
+ for (String bundleActivatorName : bundleActivators) {
+ BundleActivator activator = getBundleActivator(bundleActivatorName);
+ activator.start(m_context);
+ m_activators.add(activator);
+ }
+ }
+
+ /**
+ * Extract an agent specific configuration.
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private Dictionary getAgentConfiguration(String agent, Dictionary configuration) throws Exception {
+ String agentPrefix = agent + ".";
+ Dictionary dictionary = new Hashtable();
+
+ // first map all global properties
+ Enumeration/* <String> */keys = configuration.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (!key.startsWith(agentPrefix)) {
+ dictionary.put(key, configuration.get(key));
+ }
+ }
+
+ // overwrite with agent specific properties
+ keys = configuration.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (key.startsWith(agentPrefix)) {
+ dictionary.put(key.replaceFirst(agentPrefix, ""), configuration.get(key));
+ }
+ }
+
+ dictionary.put("agent", agent);
+ return dictionary;
+ }
+
+ /**
+ * Load the properties file from disk.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ private Dictionary loadProperties(File configurationFile) throws Exception {
+ if (!configurationFile.exists()) {
+ m_logService.log(LogService.LOG_WARNING, "Specified configuration file does not exist: " + configurationFile.getAbsolutePath());
+ return null;
+ }
+ if (!configurationFile.isFile()) {
+ m_logService.log(LogService.LOG_WARNING, "Specified configuration file is not a regular file: " + configurationFile.getAbsolutePath());
+ return null;
+ }
+ if (!configurationFile.canRead()) {
+ m_logService.log(LogService.LOG_WARNING, "Specified configuration file can not be read: " + configurationFile.getAbsolutePath());
+ return null;
+ }
+ Properties configurationProperties = new Properties();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(configurationFile);
+ configurationProperties.load(fis);
+ return configurationProperties;
+ }
+ catch (IOException e) {
+ m_logService.log(LogService.LOG_WARNING, "Specified configuration file is invalid: " + configurationFile.getAbsolutePath(), e);
+ return null;
+ }
+ finally {
+ try {
+ if (fis != null)
+ fis.close();
+ }
+ catch (IOException e) {
+ }
+ }
+ }
+
+ /**
+ * Returns a bundle activator based on the specified FQN.
+ */
+ private BundleActivator getBundleActivator(String bundleActivatorName) throws ConfigurationException {
+
+ try {
+ Class<?> clazz = StaticConfigurationHandler.class.getClassLoader().loadClass(bundleActivatorName);
+ if (!BundleActivator.class.isAssignableFrom(clazz)) {
+ throw new ConfigurationException("activators", "Factory class does not implement ComponentFactory interface: " + bundleActivatorName);
+ }
+ try {
+ Object instance = clazz.newInstance();
+ return (BundleActivator) instance;
+ }
+ catch (InstantiationException e) {
+ throw new ConfigurationException("activators", "BundleActivator class does not have a default constructor: " + bundleActivatorName);
+ }
+ catch (IllegalAccessException e) {
+ throw new ConfigurationException("activators", "BundleActivator class does not have a default constructor: " + bundleActivatorName);
+ }
+ }
+ catch (ClassNotFoundException e) {
+ throw new ConfigurationException("activators", "BundleActivator class not found: " + bundleActivatorName);
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,70 @@
+/*
+ * 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.ace.agent.logging;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.ace.agent.spi.ComponentFactoryBase;
+import org.apache.ace.log.Log;
+import org.apache.ace.log.target.store.LogStore;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Creates {@link Log} service components with a {@link LogImpl} implementation for every configured store.
+ *
+ */
+public class LogFactory extends ComponentFactoryBase {
+
+ public static final String LOG_STORES = "logstores";
+ public static final String LOG_NAME = "name";
+
+ @Override
+ public Set<Component> createComponents(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) {
+
+ Set<Component> components = new HashSet<Component>();
+ String value = configuration.get(LOG_STORES);
+ String[] stores = value.split(",");
+ for (String store : stores) {
+ components.add(createLogComponent(context, manager, logService, configuration, store.trim()));
+ }
+ return components;
+ }
+
+ private Component createLogComponent(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration, String store) {
+
+ Properties properties = getAgentproperties(configuration);
+ properties.put("name", store);
+
+ return manager.createComponent()
+ .setInterface(Log.class.getName(), properties)
+ .setImplementation(new LogImpl())
+ .add(manager.createServiceDependency()
+ .setService(LogStore.class, getAgentFilter(configuration, "(name=" + store + ")"))
+ .setRequired(true))
+ .add(manager.createServiceDependency()
+ .setService(LogService.class)
+ .setRequired(false));
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogImpl.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogImpl.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogImpl.java Tue May 7 10:25:13 2013
@@ -0,0 +1,47 @@
+/*
+ * 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.ace.agent.logging;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import org.apache.ace.log.Log;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.target.store.LogStore;
+import org.osgi.service.log.LogService;
+
+//FIXME This is a of the org.apache.ace.log it is private and may be better located here.
+
+public class LogImpl implements Log {
+ private volatile LogStore m_store;
+ private volatile LogService m_log;
+
+ public void log(int type, Dictionary properties) {
+ try {
+ m_store.put(type, properties);
+ }
+ catch (NullPointerException e) {
+ // if we cannot store the event, we log it to the normal log as extensively as possible
+ m_log.log(LogService.LOG_WARNING, "Could not store event: " + (new LogEvent("", 0, 0, 0, type, properties)).toRepresentation(), e);
+ }
+ catch (IOException e) {
+ // if we cannot store the event, we log it to the normal log as extensively as possible
+ m_log.log(LogService.LOG_WARNING, "Could not store event: " + (new LogEvent("", 0, 0, 0, type, properties)).toRepresentation(), e);
+ }
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreFactory.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreFactory.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreFactory.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreFactory.java Tue May 7 10:25:13 2013
@@ -0,0 +1,70 @@
+/*
+ * 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.ace.agent.logging;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.ace.agent.spi.ComponentFactoryBase;
+import org.apache.ace.identification.Identification;
+import org.apache.ace.log.target.store.LogStore;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * Creates {@link LogStore} service components with a {@link LogStoreImpl} implementation for every configured store.
+ *
+ */
+public class LogStoreFactory extends ComponentFactoryBase {
+
+ @Override
+ public Set<Component> createComponents(BundleContext context, DependencyManager manager, LogService logService, Map<String, String> configuration) {
+
+ Set<Component> components = new HashSet<Component>();
+ String value = configuration.get(LogFactory.LOG_STORES);
+ String[] stores = value.split(",");
+ for (String store : stores) {
+ components.add(createLogStoreComponent(context, manager, configuration, logService, store.trim()));
+ }
+ return components;
+ }
+
+ private Component createLogStoreComponent(BundleContext context, DependencyManager manager, Map<String, String> configuration, LogService logService, String store) {
+
+ Properties properties = getAgentproperties(configuration);
+ properties.put(LogFactory.LOG_NAME, store);
+
+ File baseDir = new File(context.getDataFile(""), getAgentIdentifier(configuration));
+
+ return manager.createComponent()
+ .setInterface(LogStore.class.getName(), properties)
+ .setImplementation(new LogStoreImpl(baseDir))
+ .add(manager.createServiceDependency()
+ .setService(Identification.class, getAgentFilter(configuration, null))
+ .setRequired(true))
+ .add(manager.createServiceDependency()
+ .setService(LogService.class)
+ .setRequired(false));
+ }
+}
Added: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreImpl.java?rev=1479841&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreImpl.java (added)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/logging/LogStoreImpl.java Tue May 7 10:25:13 2013
@@ -0,0 +1,561 @@
+/*
+ * 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.ace.agent.logging;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.ace.identification.Identification;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.target.store.LogStore;
+import org.osgi.service.log.LogService;
+
+//FIXME This is a of the org.apache.ace.log it is private and may be better located here.
+
+/**
+ * This class provides an implementation of the LogStore service. It tries to
+ * repair broken log files to make them readable again. However, this might lead
+ * to loss of data. Additionally, a new file is used when an error is detected.
+ */
+public class LogStoreImpl implements LogStore {
+ // injected by dependencymanager
+ volatile Identification m_identification;
+ volatile LogService m_log;
+
+ // The current store
+ private Store m_store = null;
+ private final File m_baseDir;
+ private long m_highest;
+
+ /**
+ * Create new instance using the specified directory as root directory.
+ *
+ * @param baseDir
+ * Root directory to use for storage.
+ */
+ public LogStoreImpl(File baseDir) {
+ m_baseDir = new File(baseDir, "store");
+ }
+
+ /**
+ * Init the current store.
+ *
+ * @throws java.io.IOException
+ */
+ protected synchronized void start() throws IOException {
+ if (!m_baseDir.isDirectory() && !m_baseDir.mkdirs()) {
+ throw new IllegalArgumentException("Need valid dir");
+ }
+ long current = -1;
+ File[] files = (File[]) notNull(m_baseDir.listFiles());
+ for (int i = 0; i < files.length; i++) {
+ long id = Long.parseLong(files[i].getName());
+ current = Math.max(id, current);
+ }
+ try {
+ if (current == -1) {
+ m_store = newStore();
+ } else {
+ m_store = createStore(current);
+ try {
+ m_store.init();
+ }
+ catch (IOException ex) {
+ handleException(m_store, ex);
+ }
+ }
+ }
+ catch (IOException ex) {
+ // We should be able to recover from the error.
+ m_log.log(LogService.LOG_ERROR, "Exception during log store init",
+ ex);
+ }
+ }
+
+ /**
+ * Close the current store.
+ *
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ protected synchronized void stop() throws IOException {
+ m_store.close();
+ m_store = null;
+ }
+
+ /**
+ * Create a store object for a new log.
+ *
+ * @return a store object for a new log.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ protected Store newStore() throws IOException {
+ long id = System.currentTimeMillis();
+
+ while (!(new File(m_baseDir, String.valueOf(id))).createNewFile()) {
+ id++;
+ }
+
+ return new Store(new File(m_baseDir, String.valueOf(id)), id);
+ }
+
+ /**
+ * Create a store object for the given log. This should not be used to
+ * create a new log.
+ *
+ * @param id
+ * the id of the log.
+ * @return a new store object for the given log.
+ * @throws java.io.IOException
+ * in case of an IO error.
+ */
+ protected Store createStore(long id) throws IOException {
+ return new Store(new File(m_baseDir, String.valueOf(id)), id);
+ }
+
+ /**
+ * Get the entries in the given range from the given log.
+ *
+ * @param logID
+ * the id of the log.
+ * @param from
+ * the lower bound of the range.
+ * @param to
+ * the upper bound of the range.
+ * @return a list of entries from the given log in the given range.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public synchronized List get(long logID, long from, long to)
+ throws IOException {
+ Store store = getLog(logID);
+ List result = new ArrayList();
+ try {
+ if (store.getCurrent() > from) {
+ store.reset();
+ }
+
+ while (store.hasNext()) {
+ long eventID = store.readCurrentID();
+ if ((eventID >= from) && (eventID <= to)) {
+ result.add(new LogEvent(new String(store.read())));
+ } else {
+ store.skip();
+ }
+ }
+ }
+ catch (Exception ex) {
+ handleException(store, ex);
+ }
+ finally {
+ closeIfNeeded(store);
+ }
+ return result;
+ }
+
+ /**
+ * Try to repair the given store, log the given exception and rethrow it. In
+ * case the store is the current log switch to a new one if possible.
+ *
+ * @param store
+ * the store to repair/close.
+ * @param exception
+ * the exception to log and rethrow.
+ * @throws java.io.IOException
+ * the given exception if it is an IOException else the message
+ * of the given exception wrapped in an IOException.
+ */
+ protected void handleException(Store store, Exception exception)
+ throws IOException {
+ m_log.log(LogService.LOG_WARNING, "Exception accessing the log: "
+ + store.getId(), exception);
+ if (store == m_store) {
+ m_store = newStore();
+ }
+
+ try {
+ store.truncate();
+ }
+ catch (IOException ex) {
+ m_log.log(LogService.LOG_WARNING, "Exception during truncate: "
+ + store.getId(), ex);
+ }
+ try {
+ store.close();
+ }
+ catch (IOException ex) {
+ // Not much we can do
+ }
+ if (exception instanceof IOException) {
+ throw (IOException) exception;
+ }
+ throw new IOException("Unable to read log entry: "
+ + exception.getMessage());
+ }
+
+ /**
+ * Get all entries of the given log.
+ *
+ * @param logID
+ * the id of the log.
+ * @return a list of all entries in this log.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public List get(long logID) throws IOException {
+ return get(logID, 0, Long.MAX_VALUE);
+ }
+
+ /**
+ * Get the current log ids.
+ *
+ * @return the ids of the current logs.
+ */
+ public long[] getLogIDs() throws IOException {
+ File[] files = (File[]) notNull(m_baseDir.listFiles());
+ long[] result = new long[files.length];
+ for (int i = 0; i < files.length; i++) {
+ result[i] = Long.parseLong(files[i].getName());
+ }
+ return result;
+ }
+
+ /**
+ * Create and add a LogEvent to the current log.
+ *
+ * @param type
+ * the type the event.
+ * @param props
+ * the properties of the event.
+ * @return the new event.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public synchronized LogEvent put(int type, Dictionary props) throws IOException {
+ try {
+ LogEvent result = new LogEvent(null, m_store.getId(), getNextID(), System.currentTimeMillis(), type, props);
+ m_store.append(result.getID(), result.toRepresentation().getBytes());
+ return result;
+ }
+ catch (IOException ex) {
+ handleException(m_store, ex);
+ }
+ return null;
+ }
+
+ /**
+ * Get the highest entry id of the given log.
+ *
+ * @param logID
+ * the id of the log.
+ * @return the id of the highest entry.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public synchronized long getHighestID(long logID) throws IOException {
+ Store store = getLog(logID);
+ try {
+ if (m_highest == 0) {
+ store.init();
+ return (m_highest = store.getCurrent());
+ } else {
+ return m_highest;
+ }
+ }
+ catch (IOException ex) {
+ handleException(store, ex);
+ }
+ finally {
+ closeIfNeeded(store);
+ }
+ return -1;
+ }
+
+ /**
+ * Close the given store if it is not the current store. IO errors are
+ * ignored.
+ *
+ * @param store
+ * the store to close.
+ */
+ protected void closeIfNeeded(Store store) {
+ if (store != m_store) {
+ try {
+ store.close();
+ }
+ catch (IOException ex) {
+ // Not much we can do;
+ }
+ }
+ }
+
+ /**
+ * Get a Store object for the log of the given logid.
+ *
+ * @param logID
+ * the id for which to return (and possibly create) a store.
+ * @return either a new or the current Store object.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ protected Store getLog(long logID) throws IOException {
+ if (m_store.getId() == logID) {
+ return m_store;
+ }
+ return createStore(logID);
+ }
+
+ /**
+ * Get the next id for the current store.
+ *
+ * @return the next free log id of the current store.
+ * @throws java.io.IOException
+ */
+ protected long getNextID() throws IOException {
+ return (m_highest = getHighestID(m_store.m_id) + 1);
+ }
+
+ /*
+ * throw IOException in case the target is null else return the target.
+ */
+ private Object notNull(Object target) throws IOException {
+ if (target == null) {
+ throw new IOException(
+ "Unknown IO error while trying to access the store.");
+ }
+ return target;
+ }
+
+ /**
+ * The general idea is to provide easy access to a file of records. It
+ * supports iterating over records both by skipping and by reading.
+ * Furthermore, files can be truncated. Most methods will make an effort to
+ * reset to the last good record in case of an error -- hence, a call to
+ * truncate after an IOException might make the store readable again.
+ */
+ class Store {
+ private final RandomAccessFile m_store;
+ private final long m_id;
+ private long m_current;
+
+ /**
+ * Create a new File based Store.
+ *
+ * @param store
+ * the file to use as backend.
+ * @param id
+ * the log id of the store
+ * @throws java.io.IOException
+ * in case the file is not rw.
+ */
+ Store(File store, long id) throws IOException {
+ m_store = new RandomAccessFile(store, "rwd");
+ m_id = id;
+ }
+
+ /**
+ * Get the id of the current record.
+ *
+ * @return the idea of the current record.
+ */
+ public long getCurrent() throws IOException {
+ long pos = m_store.getFilePointer();
+ if (m_store.length() == 0) {
+ return 0;
+ }
+ long result = 0;
+ try {
+ m_store.seek(m_current);
+ result = readCurrentID();
+ m_store.seek(pos);
+ }
+ catch (IOException ex) {
+ handle(pos, ex);
+ }
+ return result;
+ }
+
+ /**
+ * Get the log id of this store.
+ *
+ * @return the log id of this store.
+ */
+ public long getId() {
+ return m_id;
+ }
+
+ /**
+ * Reset the store to the beginning of the records
+ *
+ * @throws java.io.IOException
+ * in case of an IO error.
+ */
+ public void reset() throws IOException {
+ m_store.seek(0);
+ m_current = 0;
+ }
+
+ /**
+ * Determine whether there are any records left based on the current
+ * postion.
+ *
+ * @return <code>true</code> if there are still records to be read.
+ * @throws java.io.IOException
+ * in case of an IO error.
+ */
+ public boolean hasNext() throws IOException {
+ return m_store.getFilePointer() < m_store.length();
+ }
+
+ public byte[] read() throws IOException {
+ long pos = m_store.getFilePointer();
+ try {
+ if (pos < m_store.length()) {
+ long current = m_store.getFilePointer();
+ long id = m_store.readLong();
+ int next = m_store.readInt();
+ byte[] entry = new byte[next];
+ m_store.readFully(entry);
+ m_current = current;
+ return entry;
+ }
+ }
+ catch (IOException ex) {
+ handle(pos, ex);
+ }
+ return null;
+ }
+
+ public long readCurrentID() throws IOException {
+ long pos = m_store.getFilePointer();
+ try {
+ if (pos < m_store.length()) {
+ long id = m_store.readLong();
+ m_store.seek(pos);
+ return id;
+ }
+ }
+ catch (IOException ex) {
+ handle(pos, ex);
+ }
+ return -1;
+ }
+
+ /**
+ * Make sure the store is readable. As a result, the store is at the end
+ * of the records.
+ *
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public void init() throws IOException {
+ reset();
+ try {
+ while (true) {
+ skip();
+ }
+ }
+ catch (EOFException ex) {
+ // done
+ }
+ }
+
+ /**
+ * Skip the next record if there is any.
+ *
+ * @throws java.io.IOException
+ * in case of any IO error or if there is no record left.
+ */
+ public void skip() throws IOException {
+ long pos = m_store.getFilePointer();
+ try {
+ long id = m_store.readLong();
+ int next = m_store.readInt();
+ if (m_store.length() < next + m_store.getFilePointer()) {
+ throw new IOException("Unexpected end of file");
+ }
+ m_store.seek(m_store.getFilePointer() + next);
+ m_current = pos;
+ pos = m_store.getFilePointer();
+ }
+ catch (IOException ex) {
+ handle(pos, ex);
+ }
+ }
+
+ /**
+ * Store the given record data as the next record.
+ *
+ * @param entry
+ * the data of the record to store.
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public void append(long id, byte[] entry) throws IOException {
+ long pos = m_store.getFilePointer();
+ try {
+ m_store.seek(m_store.length());
+ long current = m_store.getFilePointer();
+ m_store.writeLong(id);
+ m_store.writeInt(entry.length);
+ m_store.write(entry);
+ m_store.seek(pos);
+ }
+ catch (IOException ex) {
+ handle(pos, ex);
+ }
+ }
+
+ /**
+ * Try to truncate the store at the current record.
+ *
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public void truncate() throws IOException {
+ m_store.setLength(m_store.getFilePointer());
+ }
+
+ /**
+ * Release any resources.
+ *
+ * @throws java.io.IOException
+ * in case of any IO error.
+ */
+ public void close() throws IOException {
+ m_store.close();
+ }
+
+ private void handle(long pos, IOException exception) throws IOException {
+ try {
+ m_store.seek(pos);
+ }
+ catch (IOException ex) {
+ m_log.log(LogService.LOG_WARNING, "Exception during seek!", ex);
+ }
+ throw exception;
+ }
+ }
+}
\ No newline at end of file