[libvirt] [PATCH 01/14] Introduce a simple API for handling JSON data

Daniel Veillard veillard at redhat.com
Thu Dec 3 12:11:19 UTC 2009


On Thu, Nov 26, 2009 at 06:27:19PM +0000, Daniel P. Berrange wrote:
> This introduces simple API for handling JSON data. There is
> an internal data structure 'virJSONValuePtr' which stores a
> arbitrary nested JSON value (number, string, array, object,
> nul, etc).  There are APIs for constructing/querying objects
> and APIs for parsing/formatting string formatted JSON data.
> 
> This uses the YAJL library for parsing/formatting from
> 
>  http://lloyd.github.com/yajl/

> * src/util/json.h, src/util/json.c: Data structures and APIs
>   for representing JSON data, and parsing/formatting it
> * configure.in: Add check for yajl library
> * libvirt.spec.in: Add build requires for yajl
> * src/Makefile.am: Add json.c/h
> * src/libvirt_private.syms: Export JSON symbols to drivers

  hum ... that becomes an external library, one more dependancy
on the other hand we don't have to track bug fixes.... how widely used
is yajl ?

> ---
>  configure.in             |   55 +++
>  libvirt.spec.in          |   14 +
>  po/POTFILES.in           |    1 +
>  src/Makefile.am          |    8 +-
>  src/libvirt_private.syms |   47 ++
>  src/util/json.c          | 1043 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/util/json.h          |  131 ++++++

  I see that we are encapsulating it and exposing a completely distinct
API, that's fine then, we can switch or embbed our own if needed later.

>  7 files changed, 1296 insertions(+), 3 deletions(-)
>  create mode 100644 src/util/json.c
>  create mode 100644 src/util/json.h
> 
> diff --git a/configure.in b/configure.in
> index f735bba..41f50fc 100644
> --- a/configure.in
> +++ b/configure.in
> @@ -645,6 +645,56 @@ AC_SUBST([SASL_CFLAGS])
>  AC_SUBST([SASL_LIBS])
>  
>  
> +dnl YAJL JSON library http://lloyd.github.com/yajl/
> +AC_ARG_WITH([yajl],
> +  [  --with-yajl         use YAJL for JSON parsing/formatting],
> +  [],
> +  [with_yajl=check])
> +
> +YAJL_CFLAGS=
> +YAJL_LIBS=
> +if test "x$with_yajl" != "xno"; then
> +  if test "x$with_yajl" != "xyes" -a "x$with_yajl" != "xcheck"; then
> +    YAJL_CFLAGS="-I$with_yajl/include"
> +    YAJL_LIBS="-L$with_yajl/lib"
> +  fi
> +  fail=0
> +  old_cppflags="$CPPFLAGS"
> +  old_ldflags="$LDFLAGS"
> +  CPPFLAGS="$CPPFLAGS $YAJL_CFLAGS"
> +  LDFLAGS="$LDFLAGS $YAJL_LIBS"
> +  AC_CHECK_HEADER([yajl/yajl_common.h],[],[
> +    if test "x$with_yajl" != "xcheck" ; then
> +        with_yajl=no
> +    else
> +        fail=1
> +    fi])
> +  if test "x$with_yajl" != "xno" ; then
> +    AC_CHECK_LIB([yajl], [yajl_parse],[
> +      YAJL_LIBS="$YAJL_LIBS -lyajl"
> +      with_yajl=yes
> +    ],[
> +      if test "x$with_yajl" = "xcheck" ; then
> +        with_yajl=no
> +      else
> +        fail=1
> +      fi
> +    ])
> +  fi
> +  test $fail = 1 &&
> +    AC_MSG_ERROR([You must install the YAJL development package in order to compile libvirt])
> +  CPPFLAGS="$old_cppflags"
> +  LDFLAGS="$old_ldflags"
> +  if test "x$with_yajl" = "xyes" ; then
> +    AC_DEFINE_UNQUOTED([HAVE_YAJL], 1,
> +      [whether YAJL is available for JSON parsing/formatting])
> +  fi
> +fi
> +AM_CONDITIONAL([HAVE_YAJL], [test "x$with_yajl" = "xyes"])
> +AC_SUBST([YAJL_CFLAGS])
> +AC_SUBST([YAJL_LIBS])
> +
> +
>  dnl PolicyKit library
>  POLKIT_CFLAGS=
>  POLKIT_LIBS=
> @@ -1859,6 +1909,11 @@ AC_MSG_NOTICE([    sasl: $SASL_CFLAGS $SASL_LIBS])
>  else
>  AC_MSG_NOTICE([    sasl: no])
>  fi
> +if test "$with_yajl" != "no" ; then
> +AC_MSG_NOTICE([    yajl: $YAJL_CFLAGS $YAJL_LIBS])
> +else
> +AC_MSG_NOTICE([    yajl: no])
> +fi
>  if test "$with_avahi" = "yes" ; then
>  AC_MSG_NOTICE([   avahi: $AVAHI_CFLAGS $AVAHI_LIBS])
>  else
> diff --git a/libvirt.spec.in b/libvirt.spec.in
> index dba14df..408ad05 100644
> --- a/libvirt.spec.in
> +++ b/libvirt.spec.in
> @@ -60,6 +60,7 @@
>  %define with_netcf         0%{!?_without_netcf:0}
>  %define with_udev          0%{!?_without_udev:0}
>  %define with_hal           0%{!?_without_hal:0}
> +%define with_yajl          0%{!?_without_yajl:0}
>  
>  # Non-server/HV driver defaults which are always enabled
>  %define with_python        0%{!?_without_python:1}
> @@ -141,6 +142,11 @@
>  %define with_hal       0%{!?_without_hal:%{server_drivers}}
>  %endif
>  
> +# Enable yajl library for JSON mode with QEMU
> +%if 0%{?fedora} >= 13 || 0%{?rhel} >= 6
> +%define with_yajl     0%{!?_without_yajl:%{server_drivers}}
> +%endif
> +

  yajl is not in F12, did someone add it to rawhide already ?

>  # Force QEMU to run as non-root
>  %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
>  %define qemu_user  qemu
> @@ -257,6 +263,9 @@ BuildRequires: hal-devel
>  BuildRequires: libudev-devel >= 145
>  BuildRequires: libpciaccess-devel >= 0.10.9
>  %endif
> +%if %{with_yajl}
> +BuildRequires: yajl-devel
> +%endif
>  %if %{with_avahi}
>  BuildRequires: avahi-devel
>  %endif
> @@ -495,6 +504,10 @@ of recent versions of Linux (and other OSes).
>  %define _without_udev --without-udev
>  %endif
>  
> +%if ! %{with_yajl}
> +%define _without_yajl --without-yajl
> +%endif
> +
>  %configure %{?_without_xen} \
>             %{?_without_qemu} \
>             %{?_without_openvz} \
> @@ -522,6 +535,7 @@ of recent versions of Linux (and other OSes).
>             %{?_without_selinux} \
>             %{?_without_hal} \
>             %{?_without_udev} \
> +           %{?_without_yajl} \
>             --with-qemu-user=%{qemu_user} \
>             --with-qemu-group=%{qemu_group} \
>             --with-init-script=redhat \
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 116aa87..9864259 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -50,6 +50,7 @@ src/uml/uml_driver.c
>  src/util/bridge.c
>  src/util/conf.c
>  src/util/iptables.c
> +src/util/json.c
>  src/util/logging.c
>  src/util/pci.c
>  src/util/processinfo.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 9a3c9c8..b0775a8 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -52,6 +52,7 @@ UTIL_SOURCES =							\
>  		util/hash.c util/hash.h				\
>  		util/iptables.c util/iptables.h			\
>  		util/ebtables.c util/ebtables.h			\
> +		util/json.c util/json.h				\
>  		util/logging.c util/logging.h			\
>  		util/memory.c util/memory.h			\
>  		util/pci.c util/pci.h				\
> @@ -283,8 +284,8 @@ noinst_LTLIBRARIES = libvirt_util.la
>  libvirt_la_LIBADD = libvirt_util.la
>  libvirt_util_la_SOURCES =					\
>  		$(UTIL_SOURCES)
> -libvirt_util_la_CFLAGS =  $(CAPNG_CFLAGS)
> -libvirt_util_la_LDFLAGS =  $(CAPNG_LIBS)
> +libvirt_util_la_CFLAGS =  $(CAPNG_CFLAGS) $(YAJL_CFLAGS)
> +libvirt_util_la_LDFLAGS =  $(CAPNG_LIBS) $(YAJL_LIBS)
>  
>  
>  noinst_LTLIBRARIES += libvirt_conf.la
> @@ -828,12 +829,13 @@ libvirt_lxc_SOURCES =						\
>  		$(NODE_INFO_SOURCES)				\
>  		$(ENCRYPTION_CONF_SOURCES)			\
>  		$(DOMAIN_CONF_SOURCES)
> -libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS)
> +libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) $(YAJL_LIBS)
>  libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
>  libvirt_lxc_CFLAGS =				\
>  		$(LIBPARTED_CFLAGS)		\
>  		$(NUMACTL_CFLAGS)		\
>  		$(CAPNG_CFLAGS)			\
> +		$(YAJL_CFLAGS)			\
>  		-I at top_srcdir@/src/conf
>  endif
>  endif
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index e880c2e..ee7f3ed 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -269,6 +269,53 @@ virRegisterDeviceMonitor;
>  virRegisterSecretDriver;
>  
>  
> +# json.h
> +virJSONValueFree;
> +virJSONValueNewString;
> +virJSONValueNewStringLen;
> +virJSONValueNewNumberInt;
> +virJSONValueNewNumberUint;
> +virJSONValueNewNumberLong;
> +virJSONValueNewNumberUlong;
> +virJSONValueNewNumberDouble;
> +virJSONValueNewBoolean;
> +virJSONValueNewNull;
> +virJSONValueNewArray;
> +virJSONValueNewObject;
> +virJSONValueObjectAppend;
> +virJSONValueObjectAppendString;
> +virJSONValueObjectAppendNumberInt;
> +virJSONValueObjectAppendNumberUint;
> +virJSONValueObjectAppendNumberLong;
> +virJSONValueObjectAppendNumberUlong;
> +virJSONValueObjectAppendNumberDouble;
> +virJSONValueObjectAppendBoolean;
> +virJSONValueObjectAppendNull;
> +virJSONValueArrayAppend;
> +virJSONValueObjectHasKey;
> +virJSONValueObjectGet;
> +virJSONValueArraySize;
> +virJSONValueArrayGet;
> +virJSONValueGetString;
> +virJSONValueGetNumberInt;
> +virJSONValueGetNumberUint;
> +virJSONValueGetNumberLong;
> +virJSONValueGetNumberUlong;
> +virJSONValueGetNumberDouble;
> +virJSONValueGetBoolean;
> +virJSONValueIsNull;
> +virJSONValueObjectGetString;
> +virJSONValueObjectGetNumberInt;
> +virJSONValueObjectGetNumberUint;
> +virJSONValueObjectGetNumberLong;
> +virJSONValueObjectGetNumberUlong;
> +virJSONValueObjectGetNumberDouble;
> +virJSONValueObjectGetBoolean;
> +virJSONValueObjectIsNull;
> +virJSONValueFromString;
> +virJSONValueToString;
> +
> +
>  # logging.h
>  virLogMessage;
>  virLogGetNbFilters;
> diff --git a/src/util/json.c b/src/util/json.c
> new file mode 100644
> index 0000000..f359b95
> --- /dev/null
> +++ b/src/util/json.c
> @@ -0,0 +1,1043 @@
> +/*
> + * json.h: JSON object parsing/formatting

  json.c

> + * Copyright (C) 2008 Daniel P. Berrange
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
> + *
> + */
> +
> +
> +#include <config.h>
> +
> +#include "json.h"
> +#include "memory.h"
> +#include "virterror_internal.h"
> +#include "logging.h"
> +#include "util.h"
> +
> +#include <yajl/yajl_gen.h>
> +#include <yajl/yajl_parse.h>
> +
> +/* XXX fixme */
> +#define VIR_FROM_THIS VIR_FROM_NONE

  hum, I would defined a new domain after all we have one for XML
parsing, but not urgent.

> +#define ReportError(conn, code, fmt...)                                 \
> +    virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__,           \
> +                         __FUNCTION__, __LINE__, fmt)
> +
> +
[...]
> +static virJSONValuePtr virJSONValueNewNumber(const char *data)
> +{
> +    virJSONValuePtr val;
> +
> +    if (VIR_ALLOC(val) < 0)
> +        return NULL;
> +
> +    val->type = VIR_JSON_TYPE_NUMBER;
> +    if (!(val->data.number = strdup(data))) {
> +        VIR_FREE(val);
> +        return NULL;
> +    }

  so we keep numbers as their string value ... surprizing but
maybe that's the most flexible for our use.

> +    return val;
> +}
[...]
> +
> +#if HAVE_YAJL
> +static int virJSONParserInsertValue(virJSONParserPtr parser,
> +                                    virJSONValuePtr value)

  okay so that's the YAJL specific part

[...]

> +static const yajl_callbacks parserCallbacks = {
> +    virJSONParserHandleNull,
> +    virJSONParserHandleBoolean,
> +    NULL,
> +    NULL,
> +    virJSONParserHandleNumber,
> +    virJSONParserHandleString,
> +    virJSONParserHandleStartMap,
> +    virJSONParserHandleMapKey,
> +    virJSONParserHandleEndMap,
> +    virJSONParserHandleStartArray,
> +    virJSONParserHandleEndArray
> +};

  and a driver block for it

> +
> +/* XXX add an incremental streaming parser - yajl trivially supports it */

  what would be the point ? I doubt there is a memory problem, it's more
the incremental aspect I suppose.

[...]
> +
> +#else
> +virJSONValuePtr virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED)
> +{
> +    ReprotError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("No JSON parser implementation is available"));
> +    return NULL;
> +}
> +char *virJSONValueToString(virJSONValuePtr object)
> +{
> +    ReprotError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("No JSON parser implementation is available"));
> +    return NULL;
> +}

  and the fallback


  ACK, it' weird there ain't any JSON C API yet in F12, there is one for
nearly all high level language but noone seems to have imposed a good C
one. so now we are betting on yajl, maybe another one will prevail but
since we have a good decoupling, fine by me,

  ACK

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list