/* This file is part of GNUnet. Copyright (C) 2014 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.gnunet.gns; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; import org.gnunet.construct.*; import org.gnunet.gns.records.RecordData; import org.gnunet.gns.records.UnknownRecordData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; /** * A GNS record. */ public class GnsRecord implements Message { private static final Logger logger = LoggerFactory .getLogger(GnsRecord.class); private static boolean registryInitialized; private static BiMap recordTypeMap = HashBiMap.create(); private static Map recordClassMap = Maps.newHashMap(); /** * Expiration, either absolute or relative time depending on 'flags'. */ @UInt64 public long expiration; /** * Size of 'recordDataBytes'. */ @UInt32 public long dataSize; /** * Type ID of this record. */ @UInt32 public long recordType; @UInt32 public long flags; @VariableSizeIntegerArray(lengthField = "dataSize", signed = true, bitSize = 8) public byte[] recordDataBytes; public static void initializeRegistry() { if (registryInitialized) return; Class[] classes = MessageLoader.getUnionCases(RecordData.class); for (Class aClass : classes) { String recordTypeString; try { Field field = aClass.getField("recordTypeString"); recordTypeString = (String) field.get(null); } catch (NoSuchFieldException e) { logger.warn("RecordData class {} has no recordTypeString field"); continue; } catch (IllegalAccessException e) { logger.warn("RecordData class {} can't access recordTypeString field"); continue; } long recordTypeId = MessageLoader.getUnionTag(RecordData.class, (Class) aClass); recordTypeMap.put(recordTypeString, recordTypeId); recordClassMap.put(recordTypeId, aClass); } registryInitialized = true; } public RecordData getRecordData() { initializeRegistry(); Class cls = recordClassMap.get(recordType); if (null == cls) { UnknownRecordData unknownRecordData = new UnknownRecordData(); unknownRecordData.data = recordDataBytes; } return (RecordData) Construct.parseAs(recordDataBytes, cls); } public static GnsRecord createFromString(String typeString, String content) { long typeId = getIdFromString(typeString); if (typeId < 0) return null; return createFromString(typeId, content); } public static GnsRecord createFromString(long typeId, String content) { initializeRegistry(); Class cls = recordClassMap.get(typeId); if (null == cls) { return null; } Method mth; try { mth = cls.getMethod("createFromString", String.class); } catch (NoSuchMethodException e) { return null; } try { return (GnsRecord) mth.invoke(null, content); } catch (IllegalAccessException e) { return null; } catch (InvocationTargetException e) { return null; } } public static String getStringFromId(long typeId) { initializeRegistry(); if (!recordTypeMap.inverse().containsKey(typeId)) { return null; } return recordTypeMap.inverse().get(typeId); } public static long getIdFromString(String typeString) { initializeRegistry(); if (!recordTypeMap.containsKey(typeString)) { return -1; } return recordTypeMap.get(typeString); } }