Commit d1b9693dcc49ef4b68f0ce1fb9dc65265d8a5e59

Authored by Thierry Louge
1 parent 6afd29a0

GVOTable skeleton and use through GSkymap on the way

include/GSkymap.hpp
... ... @@ -41,7 +41,8 @@
41 41 #include "GMatrix.hpp"
42 42 #include "GVector.hpp"
43 43 #include "GBilinear.hpp"
44   -
  44 +#include "GVOTable.hpp"
  45 +#include "GVOClient.hpp"
45 46  
46 47 /***********************************************************************//**
47 48 * @class GSkymap
... ... @@ -164,6 +165,8 @@ private:
164 165 void alloc_wcs(const GFitsImage& image);
165 166 GFitsBinTable* create_healpix_hdu(void) const;
166 167 GFitsImageDouble* create_wcs_hdu(void) const;
  168 + void publish(void);
  169 + void make_votable(void);
167 170  
168 171 // Private data area
169 172 int m_num_pixels; //!< Number of pixels (used for pixel allocation)
... ... @@ -172,6 +175,8 @@ private:
172 175 int m_num_y; //!< Number of pixels in y direction (only 2D)
173 176 GSkyProjection* m_proj; //!< Pointer to sky projection
174 177 double* m_pixels; //!< Pointer to skymap pixels
  178 + GVOTable* m_skytable; //!< Pointer to skymap VOTable
  179 + GVOClient* m_skyclient; //!< Pointer to VOClient opened
175 180  
176 181 // Computation cache
177 182 mutable bool m_hascache; //!< Cache is valid
... ...
include/GVOHub.hpp
... ... @@ -105,6 +105,10 @@ protected:
105 105 std::string get_hub_lockfile(void) const;
106 106 void send_notifications(const std::string& method,
107 107 const std::string& client);
  108 + void request_call(const GXml& xml,
  109 + const socklen_t& sock);
  110 + std::string get_mtype(const GXml& xml) const;
  111 + std::string get_destination(const GXml& xml) const;
108 112  
109 113 // Low-level methods
110 114 void create_samp_file(void) const;
... ...
include/GVOTable.hpp 0 → 100644
  1 +/***************************************************************************
  2 + * GVOTable.hpp - VOTable class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2014-2015 by Thierry Louge *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GVOTable.hpp
  23 + * @brief VOTable class definition
  24 + * @author Thierry Louge
  25 + */
  26 +
  27 +#ifndef GVOTable_HPP
  28 +#define GVOTable_HPP
  29 +
  30 +/* __ Definitions ________________________________________________________ */
  31 +
  32 +/* __ Includes ___________________________________________________________ */
  33 +#include <string>
  34 +#include <vector>
  35 +#include <sys/socket.h>
  36 +#include "GBase.hpp"
  37 +#include "GXml.hpp"
  38 +#include "GXmlNode.hpp"
  39 +
  40 +
  41 +/***********************************************************************//**
  42 + * @class GVOTable
  43 + *
  44 + * @brief VOTable class
  45 + *
  46 + * This class implements a VOTable for exchanges through VO-compatible
  47 + * applications.
  48 + ***************************************************************************/
  49 +class GVOTable : public GBase {
  50 +
  51 +public:
  52 + // Constructors and destructors
  53 + GVOTable(void);
  54 + GVOTable(const GVOTable& hub);
  55 + virtual ~GVOTable(void);
  56 +
  57 + // Operators
  58 + GVOTable& operator=(const GVOTable& hub);
  59 +
  60 + // Methods
  61 + void clear(void);
  62 + GVOTable* clone(void) const;
  63 + std::string classname(void) const;
  64 + std::string print(const GChatter& chatter = NORMAL) const;
  65 + void create_votable(void);
  66 + void fill_content(const std::string& data) const;
  67 +
  68 +protected:
  69 + // Protected methods
  70 + void init_members(void);
  71 + void copy_members(const GVOTable& client);
  72 + void free_members(void);
  73 +
  74 + // Low-level methods
  75 +private:
  76 + // Private data area
  77 + GXml m_tablexml; //!< GXml containing the VOTable
  78 +};
  79 +
  80 +
  81 +/***********************************************************************//**
  82 + * @brief Return class name
  83 + *
  84 + * @return String containing the class name ("GVOTable").
  85 + ***************************************************************************/
  86 +inline
  87 +std::string GVOTable::classname(void) const
  88 +{
  89 + return ("GVOTable");
  90 +}
  91 +
  92 +#endif /* GVOTable_HPP */
... ...
src/sky/GSkymap.cpp
... ... @@ -2261,7 +2261,38 @@ GFitsImageDouble* GSkymap::create_wcs_hdu(void) const
2261 2261 return hdu;
2262 2262 }
2263 2263  
  2264 +/***********************************************************************//**
  2265 + * @brief publishes the skymap in a VO Hub
  2266 + *
  2267 + * @param[in]
  2268 + *
  2269 + * @exception GException::
  2270 + *
  2271 + ***************************************************************************/
  2272 +void GSkymap::publish(void)
  2273 +{
  2274 + make_votable();
  2275 + // Return
  2276 + return;
  2277 +}
2264 2278  
  2279 +/***********************************************************************//**
  2280 + * @brief makes GVOTable object and fills ot with current skymap(s)
  2281 + *
  2282 + * @param[in]
  2283 + *
  2284 + * @exception GException::
  2285 + *
  2286 + ***************************************************************************/
  2287 +void GSkymap::make_votable(void)
  2288 +{
  2289 + GVOTable* m_skytable;
  2290 + m_skytable->create_votable();
  2291 + //For each pixel set the value of the pixel inside the data part
  2292 + //m_skytable->fill_content();
  2293 + // Return
  2294 + return;
  2295 +}
2265 2296 /*==========================================================================
2266 2297 = =
2267 2298 = Friends =
... ...
src/sky/GSkymap.cpp~ 0 → 100644
  1 +/***************************************************************************
  2 + * GSkymap.cpp - Sky map class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2010-2015 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GSkymap.cpp
  23 + * @brief Sky map class implementation
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include "GException.hpp"
  32 +#include "GTools.hpp"
  33 +#include "GSkymap.hpp"
  34 +#include "GHealpix.hpp"
  35 +#include "GWcsRegistry.hpp"
  36 +#include "GWcs.hpp"
  37 +#include "GFits.hpp"
  38 +#include "GFitsTableDoubleCol.hpp"
  39 +#include "GFitsImageDouble.hpp"
  40 +
  41 +/* __ Method name definitions ____________________________________________ */
  42 +#define G_CONSTRUCT_HPX "GSkymap::GSkymap(std::string&, int&,"\
  43 + " std::string&, int&)"
  44 +#define G_CONSTRUCT_MAP "GSkymap::GSkymap(std::string&, std::string&,"\
  45 + " double&, double&, double& double&, int&, int&, int&)"
  46 +#define G_NMAPS "GSkymap::nmaps(int&)"
  47 +#define G_OP_UNARY_ADD "GSkymap::operator+=(GSkymap&)"
  48 +#define G_OP_UNARY_SUB "GSkymap::operator-=(GSkymap&)"
  49 +#define G_OP_UNARY_MUL "GSkymap::operator-=(GSkymap&)"
  50 +#define G_OP_UNARY_DIV "GSkymap::operator-=(GSkymap&)"
  51 +#define G_OP_ACCESS_1D "GSkymap::operator(int&, int&)"
  52 +#define G_OP_ACCESS_2D "GSkymap::operator(GSkyPixel&, int&)"
  53 +#define G_OP_VALUE "GSkymap::operator(GSkyDir&, int&)"
  54 +#define G_INX2DIR "GSkymap::inx2dir(int&)"
  55 +#define G_PIX2DIR "GSkymap::pix2dir(GSkyPixel&)"
  56 +#define G_DIR2INX "GSkymap::dir2inx(GSkyDir&)"
  57 +#define G_DIR2PIX "GSkymap::dir2pix(GSkyDir&)"
  58 +#define G_SOLIDANGLE1 "GSkymap::solidangle(int&)"
  59 +#define G_SOLIDANGLE2 "GSkymap::solidangle(GSkyPixel&)"
  60 +#define G_EXTRACT "GSkymap::extract(int&, int&)"
  61 +#define G_READ "GSkymap::read(const GFitsHDU&)"
  62 +#define G_SET_WCS "GSkymap::set_wcs(std::string&, std::string&, double&,"\
  63 + " double&, double&, double&, double&, double&,"\
  64 + " GMatrix&, GVector&)"
  65 +#define G_READ_HEALPIX "GSkymap::read_healpix(GFitsTable*)"
  66 +#define G_READ_WCS "GSkymap::read_wcs(GFitsImage*)"
  67 +#define G_ALLOC_WCS "GSkymap::alloc_wcs(GFitsImage*)"
  68 +
  69 +/* __ Macros _____________________________________________________________ */
  70 +
  71 +/* __ Coding definitions _________________________________________________ */
  72 +
  73 +/* __ Debug definitions __________________________________________________ */
  74 +//#define G_READ_HEALPIX_DEBUG // Debug read_healpix
  75 +//#define G_READ_WCS_DEBUG // Debug read_wcs
  76 +
  77 +/* __ Prototype __________________________________________________________ */
  78 +
  79 +
  80 +/*==========================================================================
  81 + = =
  82 + = Constructors/destructors =
  83 + = =
  84 + ==========================================================================*/
  85 +
  86 +/***********************************************************************//**
  87 + * @brief Void constructor
  88 + ***************************************************************************/
  89 +GSkymap::GSkymap(void)
  90 +{
  91 + // Initialise class members for clean destruction
  92 + init_members();
  93 +
  94 + // Return
  95 + return;
  96 +}
  97 +
  98 +
  99 +/***********************************************************************//**
  100 + * @brief FITS file constructor
  101 + *
  102 + * @param[in] filename FITS file name.
  103 + ***************************************************************************/
  104 +GSkymap::GSkymap(const std::string& filename)
  105 +{
  106 + // Initialise class members for clean destruction
  107 + init_members();
  108 +
  109 + // Load skymap
  110 + load(filename);
  111 +
  112 + // Return
  113 + return;
  114 +}
  115 +
  116 +
  117 +/***********************************************************************//**
  118 + * @brief Healpix sky map constructor
  119 + *
  120 + * @param[in] coords Coordinate System (CEL or GAL).
  121 + * @param[in] nside Nside parameter.
  122 + * @param[in] order Pixel ordering (RING or NEST).
  123 + * @param[in] nmaps Number of maps in set (default=1).
  124 + *
  125 + * @exception GException::skymap_bad_par
  126 + * Invalid sky map parameter.
  127 + *
  128 + * Constructs sky map in Healpix pixelisation.
  129 + ***************************************************************************/
  130 +GSkymap::GSkymap(const std::string& coords,
  131 + const int& nside,
  132 + const std::string& order,
  133 + const int& nmaps)
  134 +{
  135 + // Initialise class members for clean destruction
  136 + init_members();
  137 +
  138 + // Check if nmaps parameter is >0
  139 + if (nmaps < 1) {
  140 + throw GException::skymap_bad_par(G_CONSTRUCT_HPX, nmaps,
  141 + "nmaps parameter must be >0.");
  142 + }
  143 +
  144 + // Allocate Healpix projection
  145 + GHealpix* projection = new GHealpix(nside, order, coords);
  146 + m_proj = projection;
  147 +
  148 + // Set number of pixels and number of maps
  149 + m_num_pixels = projection->npix();
  150 + m_num_maps = nmaps;
  151 +
  152 + // Allocate pixels
  153 + alloc_pixels();
  154 +
  155 + // Return
  156 + return;
  157 +}
  158 +
  159 +
  160 +/***********************************************************************//**
  161 + * @brief WCS sky map constructor
  162 + *
  163 + * @param[in] wcs World Coordinate System.
  164 + * @param[in] coords Coordinate System (CEL or GAL).
  165 + * @param[in] x X coordinate of sky map centre (deg).
  166 + * @param[in] y Y coordinate of sky map centre (deg).
  167 + * @param[in] dx Pixel size in x direction at centre (deg/pixel).
  168 + * @param[in] dy Pixel size in y direction at centre (deg/pixel).
  169 + * @param[in] nx Number of pixels in x direction.
  170 + * @param[in] ny Number of pixels in y direction.
  171 + * @param[in] nmaps Number of maps in set (default=1).
  172 + *
  173 + * @exception GException::skymap_bad_par
  174 + * Invalid sky map parameter.
  175 + *
  176 + * Constructs sky map in World Coordinate System projection.
  177 + ***************************************************************************/
  178 +GSkymap::GSkymap(const std::string& wcs,
  179 + const std::string& coords,
  180 + const double& x,
  181 + const double& y,
  182 + const double& dx,
  183 + const double& dy,
  184 + const int& nx,
  185 + const int& ny,
  186 + const int& nmaps)
  187 +{
  188 + // Initialise class members for clean destruction
  189 + init_members();
  190 +
  191 + // Check parameters
  192 + if (nx < 1) {
  193 + throw GException::skymap_bad_par(G_CONSTRUCT_MAP, nx,
  194 + "nx parameter must be >0.");
  195 + }
  196 + if (ny < 1) {
  197 + throw GException::skymap_bad_par(G_CONSTRUCT_MAP, ny,
  198 + "ny parameter must be >0.");
  199 + }
  200 + if (nmaps < 1) {
  201 + throw GException::skymap_bad_par(G_CONSTRUCT_MAP, nmaps,
  202 + "nmaps parameter must be >0.");
  203 + }
  204 +
  205 + // Set WCS
  206 + double crval1 = x;
  207 + double crval2 = y;
  208 + double crpix1 = double(nx+1)/2.0;
  209 + double crpix2 = double(ny+1)/2.0;
  210 + double cdelt1 = dx;
  211 + double cdelt2 = dy;
  212 + GMatrix cd(2,2);
  213 + GVector pv2(21);
  214 + set_wcs(wcs, coords, crval1, crval2, crpix1, crpix2, cdelt1, cdelt2,
  215 + cd, pv2);
  216 +
  217 + // Set number of pixels and number of maps
  218 + m_num_x = nx;
  219 + m_num_y = ny;
  220 + m_num_pixels = m_num_x * m_num_y;
  221 + m_num_maps = nmaps;
  222 +
  223 + // Allocate pixels
  224 + alloc_pixels();
  225 +
  226 + // Return
  227 + return;
  228 +}
  229 +
  230 +
  231 +/***********************************************************************//**
  232 + * @brief Copy constructor
  233 + *
  234 + * @param[in] map Sky map.
  235 + ***************************************************************************/
  236 +GSkymap::GSkymap(const GSkymap& map)
  237 +{
  238 + // Initialise class members for clean destruction
  239 + init_members();
  240 +
  241 + // Copy members
  242 + copy_members(map);
  243 +
  244 + // Return
  245 + return;
  246 +}
  247 +
  248 +
  249 +/***********************************************************************//**
  250 + * @brief Destructor
  251 + ***************************************************************************/
  252 +GSkymap::~GSkymap(void)
  253 +{
  254 + // Free members
  255 + free_members();
  256 +
  257 + // Return
  258 + return;
  259 +}
  260 +
  261 +
  262 +/*==========================================================================
  263 + = =
  264 + = Operators =
  265 + = =
  266 + ==========================================================================*/
  267 +
  268 +/***********************************************************************//**
  269 + * @brief Assignment operator
  270 + *
  271 + * @param[in] map Sky map.
  272 + * @return Sky map.
  273 + ***************************************************************************/
  274 +GSkymap& GSkymap::operator=(const GSkymap& map)
  275 +{
  276 + // Execute only if object is not identical
  277 + if (this != &map) {
  278 +
  279 + // Free members
  280 + free_members();
  281 +
  282 + // Initialise private members for clean destruction
  283 + init_members();
  284 +
  285 + // Copy members
  286 + copy_members(map);
  287 +
  288 + } // endif: object was not identical
  289 +
  290 + // Return this object
  291 + return *this;
  292 +}
  293 +
  294 +
  295 +/***********************************************************************//**
  296 + * @brief Value setting operator
  297 + *
  298 + * @param[in] value Value.
  299 + * @return Sky map.
  300 + *
  301 + * Sets all pixels to the specified @p value.
  302 + ***************************************************************************/
  303 +GSkymap& GSkymap::operator=(const double& value)
  304 +{
  305 + // Get number of pixels
  306 + int num = m_num_pixels * m_num_maps;
  307 +
  308 + // Loop over all pixels
  309 + for (int i = 0; i < num; ++i) {
  310 + m_pixels[i] = value;
  311 + }
  312 +
  313 + // Return this object
  314 + return *this;
  315 +}
  316 +
  317 +
  318 +/***********************************************************************//**
  319 + * @brief Map addition operator
  320 + *
  321 + * @param[in] map Sky map.
  322 + * @return Sky map.
  323 + *
  324 + * @exception GException::invalid_value
  325 + * Mismatch between number of maps in skymap object.
  326 + *
  327 + * Adds the content of @p map to the skymap. The operator only works on sky
  328 + * maps with an identical number of layers. The content is added by
  329 + * bi-linearily interpolating the values in the source sky map, allowing thus
  330 + * for a reprojection of sky map values.
  331 + *
  332 + * @todo The method is not optimized for speed as the transformation is done
  333 + * for each layer separately. A private method should be introduced that
  334 + * does the transformation, allowing the to loop more effectively over the
  335 + * layers.
  336 + ***************************************************************************/
  337 +GSkymap& GSkymap::operator+=(const GSkymap& map)
  338 +{
  339 + // Check if number of layers are identical
  340 + if (map.nmaps() != nmaps()) {
  341 + std::string msg = "Mismatch of number of maps in skymap object"
  342 + " ("+gammalib::str(nmaps())+" maps in destination"
  343 + " map, "+gammalib::str(map.nmaps())+" in source"
  344 + " map.";
  345 + throw GException::invalid_value(G_OP_UNARY_ADD, msg);
  346 + }
  347 +
  348 + // Loop over all pixels of sky map
  349 + for (int index = 0; index < npix(); ++index) {
  350 +
  351 + // Get sky direction of actual pixel
  352 + GSkyDir dir = inx2dir(index);
  353 +
  354 + // Loop over all layers
  355 + for (int layer = 0; layer < nmaps(); ++layer) {
  356 +
  357 + // Add value
  358 + (*this)(index, layer) += map(dir, layer);
  359 +
  360 + } // endfor: looped over all layers
  361 +
  362 + } // endfor: looped over all pixels
  363 +
  364 + // Return this object
  365 + return *this;
  366 +}
  367 +
  368 +
  369 +/***********************************************************************//**
  370 + * @brief Value addition operator
  371 + *
  372 + * @param[in] value Value.
  373 + * @return Sky map.
  374 + *
  375 + * Add @p value to all sky map pixels.
  376 + ***************************************************************************/
  377 +GSkymap& GSkymap::operator+=(const double& value)
  378 +{
  379 + // Set total number of sky map pixels
  380 + int num = m_num_pixels * m_num_maps;
  381 +
  382 + // Loop over all pixels of sky map
  383 + for (int i = 0; i < num; ++i) {
  384 + m_pixels[i] += value;
  385 + }
  386 +
  387 + // Return this object
  388 + return *this;
  389 +}
  390 +
  391 +
  392 +/***********************************************************************//**
  393 + * @brief Map subtraction operator
  394 + *
  395 + * @param[in] map Sky map.
  396 + * @return Sky map.
  397 + *
  398 + * @exception GException::invalid_value
  399 + * Mismatch between number of maps in skymap object.
  400 + *
  401 + * Subtracts the content of @p map from the skymap. The operator only works
  402 + * on sky maps with an identical number of layers. The content is subtracted
  403 + * by bi-linearily interpolating the values in the source sky map, allowing
  404 + * thus for a reprojection of sky map values.
  405 + *
  406 + * @todo The method is not optimized for speed as the transformation is done
  407 + * for each layer separately. A private method should be introduced that
  408 + * does the transformation, allowing the to loop more effectively over the
  409 + * layers.
  410 + ***************************************************************************/
  411 +GSkymap& GSkymap::operator-=(const GSkymap& map)
  412 +{
  413 + // Check if number of layers are identical
  414 + if (map.nmaps() != nmaps()) {
  415 + std::string msg = "Mismatch of number of maps in skymap object"
  416 + " ("+gammalib::str(nmaps())+" maps in destination"
  417 + " map, "+gammalib::str(map.nmaps())+" in source"
  418 + " map.";
  419 + throw GException::invalid_value(G_OP_UNARY_SUB, msg);
  420 + }
  421 +
  422 + // Loop over all pixels of sky map
  423 + for (int index = 0; index < npix(); ++index) {
  424 +
  425 + // Get sky direction of actual pixel
  426 + GSkyDir dir = inx2dir(index);
  427 +
  428 + // Loop over all layers
  429 + for (int layer = 0; layer < nmaps(); ++layer) {
  430 +
  431 + // Subtract value
  432 + (*this)(index, layer) -= map(dir, layer);
  433 +
  434 + } // endfor: looped over all layers
  435 +
  436 + } // endfor: looped over all pixels
  437 +
  438 + // Return this object
  439 + return *this;
  440 +}
  441 +
  442 +
  443 +/***********************************************************************//**
  444 + * @brief Value subtraction operator
  445 + *
  446 + * @param[in] value Value.
  447 + * @return Sky map.
  448 + *
  449 + * Subtracts @p value from all sky map pixels.
  450 + ***************************************************************************/
  451 +GSkymap& GSkymap::operator-=(const double& value)
  452 +{
  453 + // Set total number of sky map pixels
  454 + int num = m_num_pixels * m_num_maps;
  455 +
  456 + // Loop over all pixels of sky map
  457 + for (int i = 0; i < num; ++i) {
  458 + m_pixels[i] -= value;
  459 + }
  460 +
  461 + // Return this object
  462 + return *this;
  463 +}
  464 +
  465 +
  466 +/***********************************************************************//**
  467 + * @brief Multiplication operator
  468 + *
  469 + * @param[in] map Sky map.
  470 + * @return Sky map.
  471 + *
  472 + * @exception GException::invalid_value
  473 + * Mismatch between number of maps in skymap object.
  474 + *
  475 + * Multiplies the content of @p map from the skymap. The operator only works
  476 + * on sky maps with an identical number of layers. The content is multiplied
  477 + * by bi-linearily interpolating the values in the source sky map, allowing
  478 + * thus for a reprojection of sky map values.
  479 + *
  480 + * @todo The method is not optimized for speed as the transformation is done
  481 + * for each layer separately. A private method should be introduced that
  482 + * does the transformation, allowing to loop more effectively over the
  483 + * layers.
  484 + ***************************************************************************/
  485 +GSkymap& GSkymap::operator*=(const GSkymap& map)
  486 +{
  487 + // Check if number of layers are identical
  488 + if (map.nmaps() != nmaps()) {
  489 + std::string msg = "Mismatch of number of maps in skymap object"
  490 + " ("+gammalib::str(nmaps())+" maps in destination"
  491 + " map, "+gammalib::str(map.nmaps())+" in source"
  492 + " map.";
  493 + throw GException::invalid_value(G_OP_UNARY_MUL, msg);
  494 + }
  495 +
  496 + // Loop over all pixels of sky map
  497 + for (int index = 0; index < npix(); ++index) {
  498 +
  499 + // Get sky direction of actual pixel
  500 + GSkyDir dir = inx2dir(index);
  501 +
  502 + // Loop over all layers
  503 + for (int layer = 0; layer < nmaps(); ++layer) {
  504 +
  505 + // Subtract value
  506 + (*this)(index, layer) *= map(dir, layer);
  507 +
  508 + } // endfor: looped over all layers
  509 +
  510 + } // endfor: looped over all pixels
  511 +
  512 + // Return this object
  513 + return *this;
  514 +}
  515 +
  516 +
  517 +/***********************************************************************//**
  518 + * @brief Sky map scaling operator
  519 + *
  520 + * @param[in] factor Scale factor.
  521 + * @return Sky map.
  522 + *
  523 + * Multiplies all pixels of the sky map by the given scale @p factor.
  524 + ***************************************************************************/
  525 +GSkymap& GSkymap::operator*=(const double& factor)
  526 +{
  527 + // Compute total number of pixels
  528 + int n = npix() * nmaps();
  529 +
  530 + // Loop over all pixels
  531 + double* pixel = m_pixels;
  532 + for (int i = 0; i < n; ++i) {
  533 + *pixel++ *= factor;
  534 + }
  535 +
  536 + // Return this object
  537 + return *this;
  538 +}
  539 +
  540 +
  541 +/***********************************************************************//**
  542 + * @brief Division operator
  543 + *
  544 + * @param[in] map Sky map.
  545 + * @return Sky map.
  546 + *
  547 + * @exception GException::invalid_value
  548 + * Mismatch between number of maps in skymap object.
  549 + *
  550 + * Divides the content of @p map from the skymap. The operator only works
  551 + * on sky maps with an identical number of layers. The content is divided
  552 + * by bi-linearily interpolating the values in the source sky map, allowing
  553 + * thus for a reprojection of sky map values.
  554 + *
  555 + * @todo The method is not optimized for speed as the transformation is done
  556 + * for each layer separately. A private method should be introduced that
  557 + * does the transformation, allowing to loop more effectively over the
  558 + * layers.
  559 + ***************************************************************************/
  560 +GSkymap& GSkymap::operator/=(const GSkymap& map)
  561 +{
  562 + // Check if number of layers are identical
  563 + if (map.nmaps() != nmaps()) {
  564 + std::string msg = "Mismatch of number of maps in skymap object"
  565 + " ("+gammalib::str(nmaps())+" maps in destination"
  566 + " map, "+gammalib::str(map.nmaps())+" in source"
  567 + " map.";
  568 + throw GException::invalid_value(G_OP_UNARY_DIV, msg);
  569 + }
  570 +
  571 + // Loop over all pixels of sky map
  572 + for (int index = 0; index < npix(); ++index) {
  573 +
  574 + // Get sky direction of actual pixel
  575 + GSkyDir dir = inx2dir(index);
  576 +
  577 + // Loop over all layers
  578 + for (int layer = 0; layer < nmaps(); ++layer) {
  579 +
  580 + // Check for division by zero
  581 + if (map(dir,layer) == 0.0) {
  582 + std::string msg = "Trying to divide by zero."
  583 + " Map entries have to be strictly non-zero"
  584 + " for division";
  585 + throw GException::invalid_value(G_OP_UNARY_DIV, msg);
  586 + }
  587 +
  588 + // Subtract value
  589 + (*this)(index, layer) /= map(dir, layer);
  590 +
  591 + } // endfor: looped over all layers
  592 +
  593 + } // endfor: looped over all pixels
  594 +
  595 + // Return this object
  596 + return *this;
  597 +}
  598 +
  599 +
  600 +/***********************************************************************//**
  601 + * @brief Sky map division operator
  602 + *
  603 + * @param[in] factor Scale factor.
  604 + * @return Sky map.
  605 + *
  606 + * @exception GException::invalid_argument
  607 + * Division by zero error.
  608 + *
  609 + * Divides all pixels of the sky map by the given @p factor.
  610 + ***************************************************************************/
  611 +#define G_OP_UNARY_DIV2 "GSkymap::operator/=(double&)"
  612 +GSkymap& GSkymap::operator/=(const double& factor)
  613 +{
  614 + // Check for division by zero
  615 + if (factor == 0.0) {
  616 + std::string msg = "Trying to divide sky map pixels by zero.";
  617 + throw GException::invalid_argument(G_OP_UNARY_DIV2, msg);
  618 + }
  619 +
  620 + // Compute total number of pixels
  621 + int n = npix() * nmaps();
  622 +
  623 + // Loop over all pixels
  624 + double* pixel = m_pixels;
  625 + for (int i = 0; i < n; ++i) {
  626 + *pixel++ /= factor;
  627 + }
  628 +
  629 + // Return this object
  630 + return *this;
  631 +}
  632 +
  633 +
  634 +/***********************************************************************//**
  635 + * @brief Pixel index access operator
  636 + *
  637 + * @param[in] index Pixel index [0,...,npix()-1].
  638 + * @param[in] map Map index [0,...,nmaps()-1].
  639 + * @return Sky map pixel value.
  640 + *
  641 + * @exception GException::out_of_range
  642 + * Pixel index and/or map index are outside valid range.
  643 + *
  644 + * Access sky map pixel by its index, where the most quickly varying axis is
  645 + * the x axis of the map.
  646 + ***************************************************************************/
  647 +double& GSkymap::operator()(const int& index, const int& map)
  648 +{
  649 + // Throw an error if pixel index or map index is not in valid range
  650 + #if defined(G_RANGE_CHECK)
  651 + if (index < 0 || index >= m_num_pixels) {
  652 + throw GException::out_of_range(G_OP_ACCESS_1D,
  653 + "Sky map pixel index",
  654 + index, m_num_pixels);
  655 + }
  656 + if (map < 0 || map >= m_num_maps) {
  657 + throw GException::out_of_range(G_OP_ACCESS_1D,
  658 + "Sky map map index",
  659 + map, m_num_maps);
  660 + }
  661 + #endif
  662 +
  663 + // Return reference to pixel value
  664 + return m_pixels[index+m_num_pixels*map];
  665 +}
  666 +
  667 +
  668 +/***********************************************************************//**
  669 + * @brief Pixel index access operator (const variant)
  670 + *
  671 + * @param[in] index Pixel index [0,...,npix()-1].
  672 + * @param[in] map Map index [0,...,nmaps()-1].
  673 + *
  674 + * @exception GException::out_of_range
  675 + * Pixel index and/or map index are outside valid range.
  676 + *
  677 + * Access sky map pixel by its index, where the most quickly varying axis is
  678 + * the x axis of the map.
  679 + ***************************************************************************/
  680 +const double& GSkymap::operator()(const int& index, const int& map) const
  681 +{
  682 + // Throw an error if pixel index or map index is not in valid range
  683 + #if defined(G_RANGE_CHECK)
  684 + if (index < 0 || index >= m_num_pixels) {
  685 + throw GException::out_of_range(G_OP_ACCESS_1D,
  686 + "Sky map pixel index",
  687 + index, m_num_pixels);
  688 + }
  689 + if (map < 0 || map >= m_num_maps) {
  690 + throw GException::out_of_range(G_OP_ACCESS_1D,
  691 + "Sky map map index",
  692 + map, m_num_maps);
  693 + }
  694 + #endif
  695 +
  696 + // Return reference to pixel value
  697 + return m_pixels[index+m_num_pixels*map];
  698 +}
  699 +
  700 +
  701 +/***********************************************************************//**
  702 + * @brief Sky map pixel access operator
  703 + *
  704 + * @param[in] pixel Sky map pixel.
  705 + * @param[in] map Map index [0,...,nmaps()-1].
  706 + *
  707 + * @exception GException::out_of_range
  708 + * Sky pixel and/or map index are outside valid range.
  709 + *
  710 + * Access sky map pixel by its 2D index (x,y) that is implemented by the
  711 + * GSkyPixel class.
  712 + *
  713 + * @todo Implement proper skymap exception (actual is for matrix elements)
  714 + ***************************************************************************/
  715 +double& GSkymap::operator()(const GSkyPixel& pixel, const int& map)
  716 +{
  717 + // Throw an error if pixel index or map index is not in valid range
  718 + #if defined(G_RANGE_CHECK)
  719 + if (!contains(pixel)) {
  720 + throw GException::out_of_range(G_OP_ACCESS_2D,
  721 + int(pixel.x()), int(pixel.y()),
  722 + m_num_x-1, m_num_y-1);
  723 + }
  724 + if (map < 0 || map >= m_num_maps) {
  725 + throw GException::out_of_range(G_OP_ACCESS_2D,
  726 + "Sky map map index",
  727 + map, m_num_maps);
  728 + }
  729 + #endif
  730 +
  731 + // Get pixel index
  732 + int index = pix2inx(pixel);
  733 +
  734 + // Return reference to pixel value
  735 + return m_pixels[index+m_num_pixels*map];
  736 +}
  737 +
  738 +
  739 +/***********************************************************************//**
  740 + * @brief Sky map pixel access operator
  741 + *
  742 + * @param[in] pixel Sky map pixel.
  743 + * @param[in] map Map index [0,...,nmaps()-1].
  744 + *
  745 + * @exception GException::out_of_range
  746 + * Sky pixel and/or map index are outside valid range.
  747 + *
  748 + * Access sky map pixel by its 2D index (x,y) that is implemented by the
  749 + * GSkyPixel class.
  750 + *
  751 + * @todo Implement proper skymap exception (actual is for matrix elements)
  752 + ***************************************************************************/
  753 +const double& GSkymap::operator()(const GSkyPixel& pixel, const int& map) const
  754 +{
  755 + // Throw an error if pixel index or map index is not in valid range
  756 + #if defined(G_RANGE_CHECK)
  757 + if (!contains(pixel)) {
  758 + throw GException::out_of_range(G_OP_ACCESS_2D,
  759 + int(pixel.x()), int(pixel.y()),
  760 + m_num_x-1, m_num_y-1);
  761 + }
  762 + if (map < 0 || map >= m_num_maps) {
  763 + throw GException::out_of_range(G_OP_ACCESS_2D,
  764 + "Sky map map index",
  765 + map, m_num_maps);
  766 + }
  767 + #endif
  768 +
  769 + // Get pixel index
  770 + int index = pix2inx(pixel);
  771 +
  772 + // Return reference to pixel value
  773 + return m_pixels[index+m_num_pixels*map];
  774 +}
  775 +
  776 +
  777 +/***********************************************************************//**
  778 + * @brief Return interpolated skymap value for sky direction
  779 + *
  780 + * @param[in] dir Sky direction.
  781 + * @param[in] map Map index [0,...,nmaps()-1].
  782 + * @return Sky intensity.
  783 + *
  784 + * @exception GException::out_of_range
  785 + * Map index lies outside valid range.
  786 + *
  787 + * Returns the skymap value for a given sky direction, obtained by bi-linear
  788 + * interpolation of the neighbouring pixels. If the sky direction falls
  789 + * outside the area covered by the skymap, a value of 0 is returned.
  790 + *
  791 + * The method implements a computation cache that avoids recomputation of
  792 + * interpolation indices and weights in case that the same sky direction
  793 + * is requested several times. This speeds up use cases where skymap values
  794 + * for various map indices have to be returned for the same sky direction.
  795 + ***************************************************************************/
  796 +double GSkymap::operator()(const GSkyDir& dir, const int& map) const
  797 +{
  798 + // Throw an error if the map index is not in valid range
  799 + #if defined(G_RANGE_CHECK)
  800 + if (map < 0 || map >= m_num_maps) {
  801 + throw GException::out_of_range(G_OP_VALUE,
  802 + "Sky map map index",
  803 + map, m_num_maps);
  804 + }
  805 + #endif
  806 +
  807 + // Initialise intensity
  808 + double intensity = 0.0;
  809 +
  810 + // If the pre-computation cache has not been set or if the sky direction
  811 + // has changed then compute the bilinear interpolator
  812 + if (!m_hascache || (dir != m_last_dir)) {
  813 +
  814 + // Perform computation for HealPix map
  815 + if (m_proj->size() == 1) {
  816 +
  817 + // Get Healpix interpolator
  818 + m_interpol = static_cast<GHealpix*>(m_proj)->interpolator(dir);
  819 +
  820 + // Set containment flag and store actual sky direction as last
  821 + // direction
  822 + m_hascache = true;
  823 + m_contained = true;
  824 + m_last_dir = dir;
  825 +
  826 + } // endif: we had a Healpix projection
  827 +
  828 + // ... otherwise perform computation for WCS map
  829 + else {
  830 +
  831 + // Determine sky pixel. At this point an exception may occur
  832 + // in case that the pixel cannot be represented by the
  833 + // relevant projection. We catch this exception here
  834 + try {
  835 +
  836 + // Determine sky pixel
  837 + GSkyPixel pixel = dir2pix(dir);
  838 +
  839 + // Set containment flag and store actual sky direction
  840 + // as last direction
  841 + m_hascache = true;
  842 + m_contained = contains(pixel);
  843 + m_last_dir = dir;
  844 +
  845 + // Continue only if pixel is within the map
  846 + if (m_contained) {
  847 +
  848 + // Set left indices for interpolation. The left index is
  849 + // comprised between 0 and npixels-2. By definition, the
  850 + // right index is then the left index + 1
  851 + int inx_x = int(pixel.x());
  852 + int inx_y = int(pixel.y());
  853 + if (inx_x < 0) {
  854 + inx_x = 0;
  855 + }
  856 + else if (inx_x > m_num_x-2) {
  857 + inx_x = m_num_x - 2;
  858 + }
  859 + if (inx_y < 0) {
  860 + inx_y = 0;
  861 + }
  862 + else if (inx_y > m_num_y-2) {
  863 + inx_y = m_num_y - 2;
  864 + }
  865 +
  866 + // Set weighting factors for interpolation
  867 + double wgt_x_right = (pixel.x() - inx_x);
  868 + double wgt_x_left = 1.0 - wgt_x_right;
  869 + double wgt_y_right = (pixel.y() - inx_y);
  870 + double wgt_y_left = 1.0 - wgt_y_right;
  871 +
  872 + // Compute skymap pixel indices for bi-linear interpolation
  873 + m_interpol.index1() = inx_x + inx_y * m_num_x;
  874 + m_interpol.index2() = m_interpol.index1() + m_num_x;
  875 + m_interpol.index3() = m_interpol.index1() + 1;
  876 + m_interpol.index4() = m_interpol.index2() + 1;
  877 +
  878 + // Compute weighting factors for bi-linear interpolation
  879 + m_interpol.weight1() = wgt_x_left * wgt_y_left;
  880 + m_interpol.weight2() = wgt_x_left * wgt_y_right;
  881 + m_interpol.weight3() = wgt_x_right * wgt_y_left;
  882 + m_interpol.weight4() = wgt_x_right * wgt_y_right;
  883 +
  884 + } // endif: pixel was contained in map
  885 +
  886 + } // endtry: pixel computation was successful
  887 + catch (GException::wcs_invalid_phi_theta) {
  888 + m_contained = false;
  889 + }
  890 +
  891 + } // endelse: we had a WCS map
  892 +
  893 + } // endif: computation of the bi-linear interpolater was required
  894 +
  895 + // Compute the interpolated intensity if the pixel is contained in
  896 + // the map
  897 + if (m_contained) {
  898 +
  899 + // Compute map offset
  900 + int offset = m_num_pixels * map;
  901 +
  902 + // Compute interpolated skymap value
  903 + intensity = m_interpol(m_pixels+offset);
  904 +
  905 + } // endif: direction was contained in map
  906 +
  907 + // Return intensity
  908 + return intensity;
  909 +}
  910 +
  911 +
  912 +/*==========================================================================
  913 + = =
  914 + = Public methods =
  915 + = =
  916 + ==========================================================================*/
  917 +
  918 + /***********************************************************************//**
  919 + * @brief Clear instance.
  920 + *
  921 + * Resets the sky map to the initial state.
  922 + ***************************************************************************/
  923 +void GSkymap::clear(void)
  924 +{
  925 + // Free class members
  926 + free_members();
  927 +
  928 + // Initialise members
  929 + init_members();
  930 +
  931 + // Return
  932 + return;
  933 +}
  934 +
  935 +
  936 +/***********************************************************************//**
  937 + * @brief Clone sky map
  938 + *
  939 + * @return Pointer to deep copy of sky map.
  940 + ***************************************************************************/
  941 +GSkymap* GSkymap::clone(void) const
  942 +{
  943 + return new GSkymap(*this);
  944 +}
  945 +
  946 +
  947 +/***********************************************************************//**
  948 + * @brief Set number of maps
  949 + *
  950 + * @param[in] nmaps Number of maps.
  951 + *
  952 + * @exception GException::invalid_argument
  953 + * Invalid number of maps specified.
  954 + *
  955 + * Redefines the number of maps in an GSkymap object. If the number of maps
  956 + * is increased with respect to the existing number, additional maps with
  957 + * pixel values of zero are append to the object. Existing map pixel values
  958 + * are kept. If the number of maps is decreased with respect to the existing
  959 + * number, the excedent maps are dropped. The remaining map pixel values are
  960 + * kept.
  961 + ***************************************************************************/
  962 +void GSkymap::nmaps(const int& nmaps)
  963 +{
  964 + // Throw an exception if less than 1 map is required
  965 + if (nmaps < 1) {
  966 + std::string msg = "At least one map is required in an GSkymap object."
  967 + " Please specify an argument >=1.";
  968 + throw GException::invalid_argument(G_NMAPS, msg);
  969 + }
  970 +
  971 + // If the map has pixels and if the number of maps changes then set a new
  972 + // number of maps. Copy over any existing information.
  973 + if (m_num_pixels > 0 && nmaps != m_num_maps) {
  974 +
  975 + // Compute new skymap size
  976 + int new_size = m_num_pixels * nmaps;
  977 +
  978 + // Allocate memory for new map
  979 + double* pixels = new double[new_size];
  980 +
  981 + // Copy over existing pixels
  982 + int num_copy = (nmaps > m_num_maps) ? m_num_maps : nmaps;
  983 + num_copy *= m_num_pixels;
  984 + for (int i = 0; i < num_copy; ++i) {
  985 + pixels[i] = m_pixels[i];
  986 + }
  987 +
  988 + // Set any additional pixels to zero
  989 + if (nmaps > m_num_maps) {
  990 + for (int i = num_copy; i < new_size; ++i) {
  991 + pixels[i] = 0.0;
  992 + }
  993 + }
  994 +
  995 + // Free existing pixels
  996 + if (m_pixels != NULL) delete [] m_pixels;
  997 +
  998 + // Set pointer to stacked pixels
  999 + m_pixels = pixels;
  1000 +
  1001 + // Set number of maps
  1002 + m_num_maps = nmaps;
  1003 +
  1004 + } // endif: map had pixels
  1005 +
  1006 + // Return
  1007 + return;
  1008 +}
  1009 +
  1010 +
  1011 +/***********************************************************************//**
  1012 + * @brief Converts pixel index into sky map pixel
  1013 + *
  1014 + * @param[in] index Pixel index [0,...,npix()-1].
  1015 + * @return Sky map pixel.
  1016 + *
  1017 + * Converts the pixel @p index into a sky map pixel (GSkyPixel).The dimension
  1018 + * of GSkyPixel will be identical to the dimension of the sky map (i.e. a 1D
  1019 + * sky map leads to a 1D GSkyPixel object, a 2D sky map leads to a 2D
  1020 + * GSkyPixel object.
  1021 + ***************************************************************************/
  1022 +GSkyPixel GSkymap::inx2pix(const int& index) const
  1023 +{
  1024 + // Initialise sky map pixel
  1025 + GSkyPixel pixel;
  1026 +
  1027 + // Get x and y indices
  1028 + if (m_num_x != 0) { //!< 2D sky map
  1029 + pixel.x(double(index % m_num_x));
  1030 + pixel.y(double(index / m_num_x));
  1031 + }
  1032 + else { //!< 1D sky map
  1033 + pixel.index(index);
  1034 + }
  1035 +
  1036 + // Return pixel
  1037 + return pixel;
  1038 +}
  1039 +
  1040 +
  1041 +/***********************************************************************//**
  1042 + * @brief Returns sky direction of pixel
  1043 + *
  1044 + * @param[in] index Pixel index [0,...,npix()-1].
  1045 + * @return Sky direction.
  1046 + *
  1047 + * @exception GException::invalid_value
  1048 + * No valid sky projection found.
  1049 + *
  1050 + * Returns sky direction for a given pixel index.
  1051 + ***************************************************************************/
  1052 +GSkyDir GSkymap::inx2dir(const int& index) const
  1053 +{
  1054 + // Throw error if sky projection is not valid
  1055 + if (m_proj == NULL) {
  1056 + std::string msg = "Sky projection has not been defined.";
  1057 + throw GException::invalid_value(G_INX2DIR, msg);
  1058 + }
  1059 +
  1060 + // Determine sky direction from pixel index.
  1061 + GSkyDir dir = m_proj->pix2dir(inx2pix(index));
  1062 +
  1063 + // Return sky direction
  1064 + return dir;
  1065 +}
  1066 +
  1067 +
  1068 +/***********************************************************************//**
  1069 + * @brief Returns sky direction of pixel
  1070 + *
  1071 + * @param[in] pixel Sky map pixel.
  1072 + * @return Sky direction.
  1073 + *
  1074 + * @exception GException::invalid_value
  1075 + * No valid sky projection found.
  1076 + * @exception GException::invalid_argument
  1077 + * 2D sky map pixel used to access 1D projection.
  1078 + *
  1079 + * Returns sky direction for a given sky map @p pixel.
  1080 + ***************************************************************************/
  1081 +GSkyDir GSkymap::pix2dir(const GSkyPixel& pixel) const
  1082 +{
  1083 + // Throw error if WCS is not valid
  1084 + if (m_proj == NULL) {
  1085 + std::string msg = "Sky projection has not been defined.";
  1086 + throw GException::invalid_value(G_PIX2DIR, msg);
  1087 + }
  1088 +
  1089 + // Initialise sky direction
  1090 + GSkyDir dir;
  1091 +
  1092 + // If pixel size matches the projection size then perform a straight
  1093 + // forward conversion
  1094 + if (m_proj->size() == pixel.size()) {
  1095 + dir = m_proj->pix2dir(pixel);
  1096 + }
  1097 +
  1098 + // ... otherwise, if we have a 2D projection but a 1D pixel then
  1099 + // interpret the pixel as the linear index in the pixel array
  1100 + else if (m_proj->size() == 2) {
  1101 + dir = m_proj->pix2dir(GSkyPixel(inx2pix(int(pixel))));
  1102 + }
  1103 +
  1104 + // ... otherwise we have a 1D projection but a 2D pixel. There is
  1105 + // no unambiguous way to handle this case, hence we throw an exception
  1106 + else {
  1107 + std::string msg = "A 2-dimensional sky map pixel "+pixel.print()+
  1108 + " is used to determine the sky direction for"
  1109 + " the 1-dimensional sky projection \""+
  1110 + m_proj->name()+"\"\n"
  1111 + "Please specify a 1-dimensional sky map pixel.";
  1112 + throw GException::invalid_argument(G_PIX2DIR, msg);
  1113 + }
  1114 +
  1115 + // Return sky direction
  1116 + return dir;
  1117 +}
  1118 +
  1119 +
  1120 +/***********************************************************************//**
  1121 + * @brief Converts sky map pixel into pixel index
  1122 + *
  1123 + * @param[in] pixel Sky map pixel.
  1124 + * @return Pixel index [0,...,npix()-1].
  1125 + *
  1126 + * Converts a sky map @p pixel into the pixel index.
  1127 + ***************************************************************************/
  1128 +int GSkymap::pix2inx(const GSkyPixel& pixel) const
  1129 +{
  1130 + // Initialise pixel index
  1131 + int index = 0;
  1132 +
  1133 + // Handle 1D sky map pixel
  1134 + if (pixel.is_1D()) {
  1135 + index = int(pixel);
  1136 + }
  1137 +
  1138 + // Handle 2D sky map pixel
  1139 + else if (pixel.is_2D()) {
  1140 +
  1141 + // Get x and y indices by rounding the (x,y) values
  1142 + int ix = int(pixel.x()+0.5);
  1143 + int iy = int(pixel.y()+0.5);
  1144 +
  1145 + // Set index
  1146 + index = ix + iy * m_num_x;
  1147 +
  1148 + }
  1149 +
  1150 + // Return index
  1151 + return index;
  1152 +}
  1153 +
  1154 +
  1155 +/***********************************************************************//**
  1156 + * @brief Returns pixel index for a given sky direction
  1157 + *
  1158 + * @param[in] dir Sky direction.
  1159 + * @return Pixel index [0,...,npix()-1].
  1160 + *
  1161 + * @exception GException::invalid_value
  1162 + * No valid sky projection found.
  1163 + *
  1164 + * Returns sky map pixel index for a given sky direction.
  1165 + ***************************************************************************/
  1166 +int GSkymap::dir2inx(const GSkyDir& dir) const
  1167 +{
  1168 + // Throw error if WCS is not valid
  1169 + if (m_proj == NULL) {
  1170 + std::string msg = "Sky projection has not been defined.";
  1171 + throw GException::invalid_value(G_DIR2INX, msg);
  1172 + }
  1173 +
  1174 + // Determine pixel index for a given sky direction
  1175 + int index = pix2inx(m_proj->dir2pix(dir));
  1176 +
  1177 + // Return pixel index
  1178 + return index;
  1179 +}
  1180 +
  1181 +
  1182 +/***********************************************************************//**
  1183 + * @brief Returns sky map pixel for a given sky direction
  1184 + *
  1185 + * @param[in] dir Sky direction.
  1186 + * @return Sky map pixel.
  1187 + *
  1188 + * @exception GException::invalid_value
  1189 + * No valid sky projection found.
  1190 + *
  1191 + * Returns sky map pixel for a given sky direction.
  1192 + ***************************************************************************/
  1193 +GSkyPixel GSkymap::dir2pix(const GSkyDir& dir) const
  1194 +{
  1195 + // Throw error if WCS is not valid
  1196 + if (m_proj == NULL) {
  1197 + std::string msg = "Sky projection has not been defined.";
  1198 + throw GException::invalid_value(G_DIR2PIX, msg);
  1199 + }
  1200 +
  1201 + // Determine pixel for a given sky direction
  1202 + GSkyPixel pixel = m_proj->dir2pix(dir);
  1203 +
  1204 + // Return pixel
  1205 + return pixel;
  1206 +}
  1207 +
  1208 +
  1209 +/***********************************************************************//**
  1210 + * @brief Returns solid angle of pixel
  1211 + *
  1212 + * @param[in] index Pixel index [0,...,npix()-1].
  1213 + * @return Solid angle (steradians)
  1214 + *
  1215 + * @exception GException::invalid_value
  1216 + * No valid sky projection found.
  1217 + *
  1218 + * Returns the solid angle of the pixel with the specified @p index.
  1219 + ***************************************************************************/
  1220 +double GSkymap::solidangle(const int& index) const
  1221 +{
  1222 + // Throw error if WCS is not valid
  1223 + if (m_proj == NULL) {
  1224 + std::string msg = "Sky projection has not been defined.";
  1225 + throw GException::invalid_value(G_SOLIDANGLE1, msg);
  1226 + }
  1227 +
  1228 + // Determine solid angle from pixel index.
  1229 + double solidangle = m_proj->solidangle(inx2pix(index));
  1230 +
  1231 + // Return solid angle
  1232 + return solidangle;
  1233 +}
  1234 +
  1235 +
  1236 +/***********************************************************************//**
  1237 + * @brief Returns solid angle of pixel
  1238 + *
  1239 + * @param[in] pixel Sky map pixel.
  1240 + * @return Solid angle (steradians)
  1241 + *
  1242 + * @exception GException::invalid_value
  1243 + * No valid sky projection found.
  1244 + *
  1245 + * Returns the solid angle of the specified sky map @p pixel.
  1246 + ***************************************************************************/
  1247 +double GSkymap::solidangle(const GSkyPixel& pixel) const
  1248 +{
  1249 + // Throw error if WCS is not valid
  1250 + if (m_proj == NULL) {
  1251 + std::string msg = "Sky projection has not been defined.";
  1252 + throw GException::invalid_value(G_SOLIDANGLE2, msg);
  1253 + }
  1254 +
  1255 + // Initialise solid angle
  1256 + double solidangle = 0.0;
  1257 +
  1258 + // If pixel size matches the projection size then perform a straight
  1259 + // forward solid angle determination
  1260 + if (m_proj->size() == pixel.size()) {
  1261 + solidangle = m_proj->solidangle(pixel);
  1262 + }
  1263 +
  1264 + // ... otherwise, if we have a 2D projection but a 1D pixel then
  1265 + // interpret the pixel as the linear index in the pixel array
  1266 + else if (m_proj->size() == 2) {
  1267 + solidangle = m_proj->solidangle(GSkyPixel(inx2pix(int(pixel))));
  1268 + }
  1269 +
  1270 + // ... otherwise we have a 1D projection but a 2D pixel. There is
  1271 + // no unambiguous way to handle this case, hence we throw an exception
  1272 + else {
  1273 + std::string msg = "A 2-dimensional sky map pixel "+pixel.print()+
  1274 + " is used to determine the solid angle for"
  1275 + " the 1-dimensional sky projection \""+
  1276 + m_proj->name()+"\"\n"
  1277 + "Please specify a 1-dimensional sky map pixel.";
  1278 + throw GException::invalid_argument(G_SOLIDANGLE2, msg);
  1279 + }
  1280 +
  1281 + // Return solid angle
  1282 + return solidangle;
  1283 +}
  1284 +
  1285 +
  1286 +/***********************************************************************//**
  1287 + * @brief Set sky projection
  1288 + *
  1289 + * @param[in] proj Sky projection.
  1290 + *
  1291 + * Sets the projection from celestial to pixel coordinates. The method
  1292 + * performs a deep copy of @p proj, allowing to destroy the argument after
  1293 + * using the method.
  1294 + *
  1295 + * Warning: this method may corrupt the GSkymap object as it allows assigning
  1296 + * for example a 1D projection to a 2D skymap. Please use this method only
  1297 + * when you know what you're doing.
  1298 + *
  1299 + * @todo We may restrict this method to not allow changing the projection
  1300 + * dimension.
  1301 + ***************************************************************************/
  1302 +void GSkymap::projection(const GSkyProjection& proj)
  1303 +{
  1304 + // Free any existing WCS
  1305 + if (m_proj != NULL) delete m_proj;
  1306 +
  1307 + // Clone input WCS
  1308 + m_proj = proj.clone();
  1309 +
  1310 + // Return
  1311 + return;
  1312 +}
  1313 +
  1314 +
  1315 +/***********************************************************************//**
  1316 + * @brief Verifies if sky direction falls in map
  1317 + *
  1318 + * @param[in] dir Sky direction.
  1319 + *
  1320 + * This method checks if the specified sky direction falls within the pixels
  1321 + * covered by the skymap. The method uses the dir2xy method to convert the
  1322 + * sky direction into 2D pixel indices, and then checks whether the pixel
  1323 + * indices fall in the skymap.
  1324 + ***************************************************************************/
  1325 +bool GSkymap::contains(const GSkyDir& dir) const
  1326 +{
  1327 + // Convert sky direction into sky pixel
  1328 + GSkyPixel pixel = dir2pix(dir);
  1329 +
  1330 + // Return location flag
  1331 + return (contains(pixel));
  1332 +}
  1333 +
  1334 +
  1335 +/***********************************************************************//**
  1336 + * @brief Checks if sky map pixel falls in map
  1337 + *
  1338 + * @param[in] pixel Sky map pixel.
  1339 + * @return Trus if pixels is within map, false otherwise.
  1340 + *
  1341 + * Checks whether the specified sky map @p pixel falls within the skymap
  1342 + * or not.
  1343 + ***************************************************************************/
  1344 +bool GSkymap::contains(const GSkyPixel& pixel) const
  1345 +{
  1346 + // Initialise containment flag
  1347 + bool inmap = false;
  1348 +
  1349 + // Test 1D pixels
  1350 + if (pixel.is_1D()) {
  1351 + if (pixel.index()+0.5 >= 0.0 && pixel.index()-0.5 < m_num_pixels) {
  1352 + inmap = true;
  1353 + }
  1354 + }
  1355 +
  1356 + // Test 2D pixels
  1357 + else if (pixel.is_2D()) {
  1358 +
  1359 + // If pixel is in range then set containment flag to true
  1360 + if ((pixel.x()+0.5 >= 0.0 && pixel.x()-0.5 < m_num_x) &&
  1361 + (pixel.y()+0.5 >= 0.0 && pixel.y()-0.5 < m_num_y)) {
  1362 + inmap = true;
  1363 + }
  1364 +
  1365 + }
  1366 +
  1367 + // Return containment flag
  1368 + return inmap;
  1369 +}
  1370 +
  1371 +
  1372 +/***********************************************************************//**
  1373 + * @brief Extract maps into a new sky map object
  1374 + *
  1375 + * @param[in] map First map to extract
  1376 + * @param[in] nmaps Number of maps to extract (default: 1)
  1377 + * @return Extracted map(s).
  1378 + *
  1379 + * @exception GException::out_of_range
  1380 + * First map index outside valid range
  1381 + * @exception GException::invalid_argument
  1382 + * Requested number of maps are not available.
  1383 + *
  1384 + * Extracts @p nmaps sky maps starting from @p map from the sky map.
  1385 + ***************************************************************************/
  1386 +GSkymap GSkymap::extract(const int& map, const int& nmaps) const
  1387 +{
  1388 + // Throw an exception if the first map index is invalid
  1389 + if (map < 0 || map >= m_num_maps) {
  1390 + throw GException::out_of_range(G_EXTRACT, "Sky map index", map,
  1391 + m_num_maps);
  1392 + }
  1393 +
  1394 + // Throw an exception if the number of maps is invalid
  1395 + if (nmaps < 0) {
  1396 + std::string msg = "The number of maps to extract cannot be negative "
  1397 + "(nmaps="+gammalib::str(nmaps)+").";
  1398 + throw GException::invalid_argument(G_EXTRACT, msg);
  1399 + }
  1400 + if (nmaps > m_num_maps-map) {
  1401 + std::string msg = "The number of maps to extract ("+
  1402 + gammalib::str(nmaps)+") exceeds the number of maps "
  1403 + "that are available ("+
  1404 + gammalib::str(m_num_maps-map)+").";
  1405 + throw GException::invalid_argument(G_EXTRACT, msg);
  1406 + }
  1407 +
  1408 + // Compute memory size for extracted map
  1409 + int n_size = m_num_pixels * nmaps;
  1410 +
  1411 + // Allocate memory for extracted maps (handle the case that the
  1412 + // extracted map can be empty)
  1413 + double* pixels = NULL;
  1414 + if (n_size > 0) {
  1415 + pixels = new double[n_size];
  1416 + }
  1417 +
  1418 + // Extract pixels
  1419 + double *src = m_pixels + map*m_num_pixels;
  1420 + double *dst = pixels;
  1421 + for (int i = 0; i < n_size; ++i) {
  1422 + *dst++ = *src++;
  1423 + }
  1424 +
  1425 + // Create a copy of the map
  1426 + GSkymap result = *this;
  1427 +
  1428 + // Delete pixels from that map
  1429 + if (result.m_pixels != NULL) delete [] result.m_pixels;
  1430 +
  1431 + // Attach copied pixels to the map
  1432 + result.m_pixels = pixels;
  1433 +
  1434 + // Set number of maps
  1435 + result.m_num_maps = nmaps;
  1436 +
  1437 + // Return map
  1438 + return result;
  1439 +}
  1440 +
  1441 +
  1442 +/***********************************************************************//**
  1443 + * @brief Stack all maps into a single map
  1444 + *
  1445 + * @return Stacked map.
  1446 + *
  1447 + * The methods replaces the sky map by a version with only a single map
  1448 + * by summing over the pixel values for all maps. If the sky map has no
  1449 + * pixels or there is only a single map in the object, the method does
  1450 + * nothing.
  1451 + ***************************************************************************/
  1452 +void GSkymap::stack_maps(void)
  1453 +{
  1454 + // Continue only if the map has pixels and if there is more than 1 map
  1455 + if (m_num_pixels > 0 && m_num_maps > 1) {
  1456 +
  1457 + // Allocate memory for stacked map
  1458 + double* pixels = new double[m_num_pixels];
  1459 +
  1460 + // Stack map and save in memory
  1461 + for (int i = 0; i < m_num_pixels; ++i) {
  1462 + double sum = 0.0;
  1463 + for (int k = 0; k < m_num_maps; ++k) {
  1464 + sum += (*this)(i,k);
  1465 + }
  1466 + pixels[i] = sum;
  1467 + }
  1468 +
  1469 + // Free existing pixels
  1470 + if (m_pixels != NULL) delete [] m_pixels;
  1471 +
  1472 + // Set pointer to stacked pixels
  1473 + m_pixels = pixels;
  1474 +
  1475 + // Set number of maps to 1
  1476 + m_num_maps = 1;
  1477 +
  1478 + } // endif: map had pixels
  1479 +
  1480 + // Return
  1481 + return;
  1482 +}
  1483 +
  1484 +
  1485 +/***********************************************************************//**
  1486 + * @brief Load skymap from FITS file.
  1487 + *
  1488 + * @param[in] filename FITS file name..
  1489 + *
  1490 + * Loads HEALPix and non HEALPix skymaps. First searches for HEALPix map in
  1491 + * FITS file by scanning all HDUs for PIXTYPE=HEALPIX. If no HEALPix map has
  1492 + * been found then search load first non-empty image.
  1493 + *
  1494 + * @todo Do we have to restrict a HEALPix map to a BinTable and a WCS map
  1495 + * to a Double precision image???
  1496 + ***************************************************************************/
  1497 +void GSkymap::load(const std::string& filename)
  1498 +{
  1499 + // Free memory and initialise members
  1500 + free_members();
  1501 + init_members();
  1502 +
  1503 + // Open FITS file
  1504 + GFits fits(filename);
  1505 +
  1506 + // Get number of HDUs
  1507 + int num = fits.size();
  1508 +
  1509 + // Initialize load flag
  1510 + bool loaded = false;
  1511 +
  1512 + // First search for HEALPix extension. We can skip the first extension
  1513 + // since this is always an image and a HEALPix map is stored in a
  1514 + // binary table
  1515 + for (int extno = 1; extno < num; ++extno) {
  1516 +
  1517 + // Get reference to HDU
  1518 + const GFitsHDU& hdu = *fits.at(extno);
  1519 +
  1520 + // If PIXTYPE keyword equals "HEALPIX" then load map
  1521 + if (hdu.has_card("PIXTYPE") && hdu.string("PIXTYPE") == "HEALPIX") {
  1522 + read_healpix(static_cast<const GFitsTable&>(hdu));
  1523 + loaded = true;
  1524 + break;
  1525 + }
  1526 +
  1527 + } // endfor: looped over HDUs
  1528 +
  1529 + // If we have not found a HEALPIX map then search now for image.
  1530 + // Skip empty images
  1531 + if (!loaded) {
  1532 + for (int extno = 0; extno < num; ++extno) {
  1533 +
  1534 + // Get referene to HDU
  1535 + const GFitsHDU& hdu = *fits.at(extno);
  1536 +
  1537 + // Skip if extension is not an image
  1538 + if (extno > 0) {
  1539 + if (hdu.string("XTENSION") != "IMAGE")
  1540 + continue;
  1541 + }
  1542 +
  1543 + // Load WCS map
  1544 + read_wcs(static_cast<const GFitsImage&>(hdu));
  1545 + //loaded = true;
  1546 + break;
  1547 +
  1548 + } // endfor: looped over HDUs
  1549 + } // endif: no HEALPix map found
  1550 +
  1551 + // Close FITS file
  1552 + fits.close();
  1553 +
  1554 + // Return
  1555 + return;
  1556 +}
  1557 +
  1558 +
  1559 +/***********************************************************************//**
  1560 + * @brief Save skymap into FITS file.
  1561 + *
  1562 + * @param[in] filename FITS file name.
  1563 + * @param[in] clobber Overwrite existing file? (true=yes)
  1564 + *
  1565 + * The method does nothing if the skymap holds no valid WCS.
  1566 + ***************************************************************************/
  1567 +void GSkymap::save(const std::string& filename, bool clobber) const
  1568 +{
  1569 + // Continue only if we have data to save
  1570 + if (m_proj != NULL) {
  1571 +
  1572 + // Initialise HDU pointer
  1573 + GFitsHDU* hdu = NULL;
  1574 +
  1575 + // Case A: Skymap is Healpix
  1576 + if (m_proj->code() == "HPX") {
  1577 + hdu = create_healpix_hdu();
  1578 + }
  1579 +
  1580 + // Case B: Skymap is not Healpix
  1581 + else {
  1582 + hdu = create_wcs_hdu();
  1583 + }
  1584 +
  1585 + // Create FITS file and save it to disk
  1586 + if (hdu != NULL) {
  1587 + GFits fits;
  1588 + fits.append(*hdu);
  1589 + fits.saveto(filename, clobber);
  1590 + }
  1591 +
  1592 + // Delete HDU
  1593 + if (hdu != NULL) delete hdu;
  1594 +
  1595 + } // endif: we had data to save
  1596 +
  1597 + // Return
  1598 + return;
  1599 +}
  1600 +
  1601 +
  1602 +/***********************************************************************//**
  1603 + * @brief Read skymap from FITS HDU
  1604 + *
  1605 + * @param[in] hdu FITS HDU.
  1606 + ***************************************************************************/
  1607 +void GSkymap::read(const GFitsHDU& hdu)
  1608 +{
  1609 + // Free memory and initialise members
  1610 + free_members();
  1611 + init_members();
  1612 +
  1613 + // Initialize load flag
  1614 + bool loaded = false;
  1615 +
  1616 + // If PIXTYPE keyword equals "HEALPIX" then load map
  1617 + if (hdu.has_card("PIXTYPE") && hdu.string("PIXTYPE") == "HEALPIX") {
  1618 + read_healpix(static_cast<const GFitsTable&>(hdu));
  1619 + loaded = true;
  1620 + }
  1621 +
  1622 + // ... otherwise try loading as non HEALPix map
  1623 + if (!loaded) {
  1624 +
  1625 + // Load only if HDU contains an image
  1626 + if (hdu.exttype() == 0) {
  1627 + read_wcs(static_cast<const GFitsImage&>(hdu));
  1628 + //loaded = true;
  1629 + }
  1630 +
  1631 + } // endif
  1632 +
  1633 + // Return
  1634 + return;
  1635 +}
  1636 +
  1637 +
  1638 +/***********************************************************************//**
  1639 + * @brief Write skymap into FITS file
  1640 + *
  1641 + * @param[in] file FITS file pointer.
  1642 + ***************************************************************************/
  1643 +void GSkymap::write(GFits& file) const
  1644 +{
  1645 + // Continue only if we have data to save
  1646 + if (m_proj != NULL) {
  1647 +
  1648 + // Initialise HDU pointer
  1649 + GFitsHDU* hdu = NULL;
  1650 +
  1651 + // Case A: Skymap is Healpix
  1652 + if (m_proj->code() == "HPX") {
  1653 + hdu = create_healpix_hdu();
  1654 + }
  1655 +
  1656 + // Case B: Skymap is not Healpix
  1657 + else {
  1658 + hdu = create_wcs_hdu();
  1659 + }
  1660 +
  1661 + // Append HDU to FITS file.
  1662 + if (hdu != NULL) {
  1663 + file.append(*hdu);
  1664 + }
  1665 +
  1666 + // Delete HDU
  1667 + if (hdu != NULL) delete hdu;
  1668 +
  1669 + } // endif: we had data to save
  1670 +
  1671 + // Return
  1672 + return;
  1673 +}
  1674 +
  1675 +
  1676 +/***********************************************************************//**
  1677 + * @brief Print sky map
  1678 + *
  1679 + * @param[in] chatter Chattiness (defaults to NORMAL).
  1680 + * @return String containing sky map information.
  1681 + ***************************************************************************/
  1682 +std::string GSkymap::print(const GChatter& chatter) const
  1683 +{
  1684 + // Initialise result string
  1685 + std::string result;
  1686 +
  1687 + // Continue only if chatter is not silent
  1688 + if (chatter != SILENT) {
  1689 +
  1690 + // Append header
  1691 + result.append("=== GSkymap ===");
  1692 +
  1693 + // Append information
  1694 + result.append("\n"+gammalib::parformat("Number of pixels"));
  1695 + result.append(gammalib::str(m_num_pixels));
  1696 + result.append("\n"+gammalib::parformat("Number of maps"));
  1697 + result.append(gammalib::str(m_num_maps));
  1698 + if (m_proj != NULL && m_proj->size() == 2) {
  1699 + result.append("\n"+gammalib::parformat("X axis dimension"));
  1700 + result.append(gammalib::str(m_num_x));
  1701 + result.append("\n"+gammalib::parformat("Y axis dimension"));
  1702 + result.append(gammalib::str(m_num_y));
  1703 + }
  1704 +
  1705 + // Append sky projection information
  1706 + if (gammalib::reduce(chatter) > SILENT) {
  1707 + if (m_proj != NULL) {
  1708 + result.append("\n"+m_proj->print(gammalib::reduce(chatter)));
  1709 + }
  1710 + else {
  1711 + result.append("\n"+gammalib::parformat("Sky projection"));
  1712 + result.append("not defined");
  1713 + }
  1714 + }
  1715 +
  1716 + } // endif: chatter was not silent
  1717 +
  1718 + // Return result
  1719 + return result;
  1720 +}
  1721 +
  1722 +/*==========================================================================
  1723 + = =
  1724 + = Private methods =
  1725 + = =
  1726 + ==========================================================================*/
  1727 +
  1728 +/***********************************************************************//**
  1729 + * @brief Initialise class members
  1730 + ***************************************************************************/
  1731 +void GSkymap::init_members(void)
  1732 +{
  1733 + // Initialise members
  1734 + m_num_pixels = 0;
  1735 + m_num_maps = 0;
  1736 + m_num_x = 0;
  1737 + m_num_y = 0;
  1738 + m_proj = NULL;
  1739 + m_pixels = NULL;
  1740 +
  1741 + // Initialise computation cache
  1742 + m_hascache = false;
  1743 + m_contained = false;
  1744 + m_last_dir.clear();
  1745 + m_interpol.clear();
  1746 +
  1747 + // Return
  1748 + return;
  1749 +}
  1750 +
  1751 +
  1752 +/***********************************************************************//**
  1753 + * @brief Allocate skymap pixels
  1754 + ***************************************************************************/
  1755 +void GSkymap::alloc_pixels(void)
  1756 +{
  1757 + // Compute data size
  1758 + int size = m_num_pixels * m_num_maps;
  1759 +
  1760 + // Continue only if there are pixels
  1761 + if (size > 0) {
  1762 +
  1763 + // Allocate pixels and initialize them to 0
  1764 + m_pixels = new double[size];
  1765 + for (int i = 0; i < size; ++i) {
  1766 + m_pixels[i] = 0.0;
  1767 + }
  1768 +
  1769 + } // endif: there were pixels
  1770 +
  1771 + // Return
  1772 + return;
  1773 +}
  1774 +
  1775 +
  1776 +/***********************************************************************//**
  1777 + * @brief Copy class members
  1778 + *
  1779 + * @param[in] map Sky map.
  1780 + ***************************************************************************/
  1781 +void GSkymap::copy_members(const GSkymap& map)
  1782 +{
  1783 + // Copy attributes
  1784 + m_num_pixels = map.m_num_pixels;
  1785 + m_num_maps = map.m_num_maps;
  1786 + m_num_x = map.m_num_x;
  1787 + m_num_y = map.m_num_y;
  1788 +
  1789 + // Copy computation cache
  1790 + m_hascache = map.m_hascache;
  1791 + m_contained = map.m_contained;
  1792 + m_last_dir = map.m_last_dir;
  1793 + m_interpol = map.m_interpol;
  1794 +
  1795 + // Clone sky projection if it is valid
  1796 + if (map.m_proj != NULL) m_proj = map.m_proj->clone();
  1797 +
  1798 + // Compute data size
  1799 + int size = m_num_pixels * m_num_maps;
  1800 +
  1801 + // Copy pixels
  1802 + if (size > 0 && map.m_pixels != NULL) {
  1803 + alloc_pixels();
  1804 + for (int i = 0; i < size; ++i) {
  1805 + m_pixels[i] = map.m_pixels[i];
  1806 + }
  1807 + }
  1808 +
  1809 + // Return
  1810 + return;
  1811 +}
  1812 +
  1813 +
  1814 +/***********************************************************************//**
  1815 + * @brief Delete class members
  1816 + ***************************************************************************/
  1817 +void GSkymap::free_members(void)
  1818 +{
  1819 + // Free memory
  1820 + if (m_proj != NULL) delete m_proj;
  1821 + if (m_pixels != NULL) delete [] m_pixels;
  1822 +
  1823 + // Signal free pointers
  1824 + m_proj = NULL;
  1825 + m_pixels = NULL;
  1826 +
  1827 + // Reset number of pixels
  1828 + m_num_pixels = 0;
  1829 + m_num_maps = 0;
  1830 + m_num_x = 0;
  1831 + m_num_y = 0;
  1832 +
  1833 + // Return
  1834 + return;
  1835 +}
  1836 +
  1837 +
  1838 +/***********************************************************************//**
  1839 + * @brief Set World Coordinate System
  1840 + *
  1841 + * @param[in] wcs World Coordinate System code.
  1842 + * @param[in] coords Coordinate system.
  1843 + * @param[in] crval1 X value of reference pixel.
  1844 + * @param[in] crval2 Y value of reference pixel.
  1845 + * @param[in] crpix1 X index of reference pixel.
  1846 + * @param[in] crpix2 Y index of reference pixel.
  1847 + * @param[in] cdelt1 Increment in x direction at reference pixel (deg).
  1848 + * @param[in] cdelt2 Increment in y direction at reference pixel (deg).
  1849 + * @param[in] cd Astrometry parameters (2x2 matrix, deg/pixel).
  1850 + * @param[in] pv2 Projection parameters (length WCS type dependent).
  1851 + *
  1852 + * @exception GException::wcs_invalid
  1853 + * Invalid wcs parameter (World Coordinate System not known).
  1854 + *
  1855 + * This method sets the WCS projection pointer based on the WCS code and
  1856 + * sky map parameters. It makes use of the GWcsRegistry class to allocate
  1857 + * the correct derived class. Note that this method does not support the
  1858 + * HPX projection.
  1859 + *
  1860 + * @todo Remove cd and pv2 parameters.
  1861 + ***************************************************************************/
  1862 +void GSkymap::set_wcs(const std::string& wcs, const std::string& coords,
  1863 + const double& crval1, const double& crval2,
  1864 + const double& crpix1, const double& crpix2,
  1865 + const double& cdelt1, const double& cdelt2,
  1866 + const GMatrix& cd, const GVector& pv2)
  1867 +{
  1868 + // Convert WCS to upper case
  1869 + std::string uwcs = gammalib::toupper(wcs);
  1870 +
  1871 + // Check if HPX was requested (since this is not allowed)
  1872 + if (uwcs == "HPX") {
  1873 + throw GException::wcs_invalid(G_SET_WCS, uwcs,
  1874 + "Method not valid for HPX projection.");
  1875 + }
  1876 +
  1877 + // ... otherwise get projection from registry
  1878 + else {
  1879 + // Allocate WCS registry
  1880 + GWcsRegistry registry;
  1881 +
  1882 + // Allocate projection from registry
  1883 + GWcs* projection = registry.alloc(uwcs);
  1884 + m_proj = projection;
  1885 +
  1886 + // Signal if projection type is not known
  1887 + if (projection == NULL) {
  1888 + std::string message = "Projection code not known. "
  1889 + "Should be one of "+registry.list()+".";
  1890 + throw GException::wcs_invalid(G_SET_WCS, uwcs, message);
  1891 + }
  1892 +
  1893 + // Setup WCS
  1894 + projection->set(coords, crval1, crval2, crpix1, crpix2,
  1895 + cdelt1, cdelt2);
  1896 +
  1897 + } // endelse: got projection from registry
  1898 +
  1899 + // Return
  1900 + return;
  1901 +}
  1902 +
  1903 +
  1904 +/***********************************************************************//**
  1905 + * @brief Read Healpix data from FITS table.
  1906 + *
  1907 + * @param[in] table FITS table.
  1908 + *
  1909 + * HEALPix data may be stored in various formats depending on the
  1910 + * application that has writted the data. HEALPix IDL, for example, may
  1911 + * store the data in vectors of length 1024 if the number of pixels is
  1912 + * a multiple of 1024. On the other hand, vectors may also be used to store
  1913 + * several HEALPix maps into a single column. Alternatively, multiple maps
  1914 + * may be stored in multiple columns.
  1915 + ***************************************************************************/
  1916 +void GSkymap::read_healpix(const GFitsTable& table)
  1917 +{
  1918 + // Determine number of rows and columns in table
  1919 + int nrows = table.nrows();
  1920 + int ncols = table.ncols();
  1921 + #if defined(G_READ_HEALPIX_DEBUG)
  1922 + std::cout << "nrows=" << nrows << " ncols=" << ncols << std::endl;
  1923 + #endif
  1924 +
  1925 + // Allocate Healpix projection
  1926 + m_proj = new GHealpix;
  1927 +
  1928 + // Read WCS information from FITS header
  1929 + m_proj->read(table);
  1930 +
  1931 + // Set number of pixels based on NSIDE parameter
  1932 + m_num_pixels = static_cast<GHealpix*>(m_proj)->npix();
  1933 + #if defined(G_READ_HEALPIX_DEBUG)
  1934 + std::cout << "m_num_pixels=" << m_num_pixels << std::endl;
  1935 + #endif
  1936 +
  1937 + // Number of map pixels has to be a multiple of the number of
  1938 + // rows in column
  1939 + if (m_num_pixels % nrows != 0) {
  1940 + throw GException::skymap_bad_size(G_READ_HEALPIX, nrows,
  1941 + m_num_pixels);
  1942 + }
  1943 +
  1944 + // Determine vector length for HEALPix data storage
  1945 + int nentry = m_num_pixels / nrows;
  1946 + #if defined(G_READ_HEALPIX_DEBUG)
  1947 + std::cout << "nentry=" << nentry << std::endl;
  1948 + #endif
  1949 +
  1950 + // Determine number of maps from the number of maps that fit into
  1951 + // all columns. Only count columns that can fully hold the map.
  1952 + m_num_maps = 0;
  1953 + for (int icol = 0; icol < ncols; ++icol) {
  1954 + const GFitsTableCol* col = table[icol];
  1955 + if (col->number() % nentry == 0) {
  1956 + m_num_maps += col->number() / nentry;
  1957 + }
  1958 + }
  1959 + #if defined(G_READ_HEALPIX_DEBUG)
  1960 + std::cout << "m_num_maps=" << m_num_maps << std::endl;
  1961 + #endif
  1962 +
  1963 + // Allocate pixels to hold the map
  1964 + alloc_pixels();
  1965 +
  1966 + // Initialise map counter
  1967 + int imap = 0;
  1968 +
  1969 + // Loop over all columns
  1970 + for (int icol = 0; icol < ncols; ++icol) {
  1971 +
  1972 + // Get next column
  1973 + const GFitsTableCol* col = table[icol];
  1974 +
  1975 + // Only consider columns that can fully hold maps
  1976 + if (col->number() % nentry == 0) {
  1977 +
  1978 + // Determine number of maps in column
  1979 + int num = col->number() / nentry;
  1980 +
  1981 + // Loop over all maps in column
  1982 + int inx_start = 0;
  1983 + int inx_end = nentry;
  1984 + for (int i = 0; i < num; ++i) {
  1985 +
  1986 + // Load map
  1987 + double *ptr = m_pixels + m_num_pixels*imap;
  1988 + for (int row = 0; row < col->length(); ++row) {
  1989 + for (int inx = inx_start; inx < inx_end; ++inx) {
  1990 + *ptr++ = col->real(row,inx);
  1991 + }
  1992 + }
  1993 + #if defined(G_READ_HEALPIX_DEBUG)
  1994 + std::cout << "Load map=" << imap << " index="
  1995 + << inx_start << "-" << inx_end << std::endl;
  1996 + #endif
  1997 +
  1998 + // Increment index range
  1999 + inx_start = inx_end;
  2000 + inx_end += nentry;
  2001 +
  2002 + // Increment map counter
  2003 + imap++;
  2004 +
  2005 + // Break if we have loaded all maps
  2006 + if (imap >= m_num_maps) {
  2007 + break;
  2008 + }
  2009 +
  2010 + } // endfor: looped over all maps in column
  2011 + } // endif: column could fully hold maps
  2012 +
  2013 + // Break if we have loaded all maps
  2014 + if (imap >= m_num_maps) {
  2015 + break;
  2016 + }
  2017 +
  2018 + } // endfor: looped over all columns
  2019 +
  2020 + // Return
  2021 + return;
  2022 +}
  2023 +
  2024 +
  2025 +/***********************************************************************//**
  2026 + * @brief Read WCS image from FITS HDU
  2027 + *
  2028 + * @param[in] image FITS image.
  2029 + *
  2030 + * @exception GException::skymap_bad_image_dim
  2031 + * WCS image has invalid dimension (naxis=2 or 3).
  2032 + ***************************************************************************/
  2033 +void GSkymap::read_wcs(const GFitsImage& image)
  2034 +{
  2035 + // Allocate WCS
  2036 + alloc_wcs(image);
  2037 +
  2038 + // Read projection information from FITS header
  2039 + m_proj->read(image);
  2040 +
  2041 + // Extract map dimension and number of maps from image
  2042 + if (image.naxis() == 2) {
  2043 + m_num_x = image.naxes(0);
  2044 + m_num_y = image.naxes(1);
  2045 + m_num_maps = 1;
  2046 + }
  2047 + else if (image.naxis() >= 3) {
  2048 + m_num_x = image.naxes(0);
  2049 + m_num_y = image.naxes(1);
  2050 + m_num_maps = image.naxes(2);
  2051 + }
  2052 + else {
  2053 + throw GException::skymap_bad_image_dim(G_READ_WCS, image.naxis());
  2054 + }
  2055 + #if defined(G_READ_WCS_DEBUG)
  2056 + std::cout << "m_num_x=" << m_num_x << std::endl;
  2057 + std::cout << "m_num_y=" << m_num_y << std::endl;
  2058 + std::cout << "m_num_maps=" << m_num_maps << std::endl;
  2059 + #endif
  2060 +
  2061 + // Compute number of pixels
  2062 + m_num_pixels = m_num_x * m_num_y;
  2063 + #if defined(G_READ_WCS_DEBUG)
  2064 + std::cout << "m_num_pixels=" << m_num_pixels << std::endl;
  2065 + #endif
  2066 +
  2067 + // Allocate pixels to hold the map
  2068 + alloc_pixels();
  2069 +
  2070 + // Read image
  2071 + if (image.naxis() == 2) {
  2072 + double* ptr = m_pixels;
  2073 + for (int iy = 0; iy < m_num_y; ++iy) {
  2074 + for (int ix = 0; ix < m_num_x; ++ix) {
  2075 + *ptr++ = image.pixel(ix,iy);
  2076 + }
  2077 + }
  2078 + }
  2079 + else {
  2080 + double* ptr = m_pixels;
  2081 + for (int imap = 0; imap < m_num_maps; ++imap) {
  2082 + for (int iy = 0; iy < m_num_y; ++iy) {
  2083 + for (int ix = 0; ix < m_num_x; ++ix) {
  2084 + *ptr++ = image.pixel(ix,iy,imap);
  2085 + }
  2086 + }
  2087 + }
  2088 + }
  2089 +
  2090 + // Return
  2091 + return;
  2092 +}
  2093 +
  2094 +
  2095 +/***********************************************************************//**
  2096 + * @brief Allocate WCS class
  2097 + *
  2098 + * @param[in] image FITS image.
  2099 + *
  2100 + * @exception GException::fits_key_not_found
  2101 + * Unable to find required FITS header keyword.
  2102 + * @exception GException::skymap_bad_ctype
  2103 + * CTYPE1 and CTYPE2 keywords are incompatible.
  2104 + * @exception GException::wcs_invalid
  2105 + * WCS projection of FITS file not supported by GammaLib.
  2106 + ***************************************************************************/
  2107 +void GSkymap::alloc_wcs(const GFitsImage& image)
  2108 +{
  2109 + // Get standard keywords
  2110 + std::string ctype1 = image.string("CTYPE1");
  2111 + std::string ctype2 = image.string("CTYPE2");
  2112 +
  2113 + // Extract projection type
  2114 + std::string xproj = ctype1.substr(5,3);
  2115 + std::string yproj = ctype2.substr(5,3);
  2116 +
  2117 + // Check that projection type is identical on both axes
  2118 + if (xproj != yproj) {
  2119 + throw GException::skymap_bad_ctype(G_ALLOC_WCS,
  2120 + ctype1, ctype2);
  2121 + }
  2122 +
  2123 + // Allocate WCS registry
  2124 + GWcsRegistry registry;
  2125 +
  2126 + // Allocate projection from registry
  2127 + m_proj = registry.alloc(xproj);
  2128 +
  2129 + // Signal if projection type is not known
  2130 + if (m_proj == NULL) {
  2131 + std::string message = "Projection code not known. "
  2132 + "Should be one of "+registry.list()+".";
  2133 + throw GException::wcs_invalid(G_ALLOC_WCS, xproj, message);
  2134 + }
  2135 +
  2136 + // Return
  2137 + return;
  2138 +}
  2139 +
  2140 +
  2141 +/***********************************************************************//**
  2142 + * @brief Create FITS HDU containing Healpix data
  2143 + *
  2144 + * This method allocates a binary table HDU that contains the Healpix data.
  2145 + * Deallocation of the table has to be done by the client.
  2146 + ***************************************************************************/
  2147 +GFitsBinTable* GSkymap::create_healpix_hdu(void) const
  2148 +{
  2149 + // Initialise result to NULL pointer
  2150 + GFitsBinTable* hdu = NULL;
  2151 +
  2152 + // Compute size of Healpix data
  2153 + int size = m_num_pixels * m_num_maps;
  2154 +
  2155 + // Continue only if we have pixels
  2156 + if (size > 0) {
  2157 +
  2158 + // Set number of rows and columns
  2159 + int rows = m_num_pixels;
  2160 + int number = m_num_maps;
  2161 +
  2162 + // Create column to hold Healpix data
  2163 + GFitsTableDoubleCol column = GFitsTableDoubleCol("DATA", rows, number);
  2164 +
  2165 + // Fill data into column
  2166 + double* ptr = m_pixels;
  2167 + for (int inx = 0; inx < number; ++inx) {
  2168 + for (int row = 0; row < rows; ++row) {
  2169 + column(row,inx) = *ptr++;
  2170 + }
  2171 + }
  2172 +
  2173 + // Create HDU that contains Healpix map in a binary table
  2174 + hdu = new GFitsBinTable(rows);
  2175 + hdu->append(column);
  2176 +
  2177 + } // endif: there were pixels
  2178 +
  2179 + // ... otherwise create an empty header
  2180 + else {
  2181 + hdu = new GFitsBinTable;
  2182 + }
  2183 +
  2184 + // Set extension name
  2185 + hdu->extname("HEALPIX");
  2186 +
  2187 + // If we have WCS information then write into FITS header
  2188 + if (m_proj != NULL) m_proj->write(*hdu);
  2189 +
  2190 + // Set additional keywords
  2191 + hdu->card("NBRBINS", m_num_maps, "Number of HEALPix maps");
  2192 +
  2193 + // Return HDU
  2194 + return hdu;
  2195 +}
  2196 +
  2197 +
  2198 +/***********************************************************************//**
  2199 + * @brief Create FITS HDU containing WCS image
  2200 + *
  2201 + * This method allocates an image HDU that contains the WCS image data.
  2202 + * Deallocation of the image has to be done by the client.
  2203 + *
  2204 + * @todo Set additional keywords.
  2205 + ***************************************************************************/
  2206 +GFitsImageDouble* GSkymap::create_wcs_hdu(void) const
  2207 +{
  2208 + // Initialise result to NULL pointer
  2209 + GFitsImageDouble* hdu = NULL;
  2210 +
  2211 + // Compute size of Healpix data
  2212 + int size = m_num_pixels * m_num_maps;
  2213 +
  2214 + // Continue only if we have pixels
  2215 + if (size > 0) {
  2216 +
  2217 + // Set axis parameters for image construction
  2218 + int naxis = (m_num_maps == 1) ? 2 : 3;
  2219 + int naxes[] = {m_num_x, m_num_y, m_num_maps};
  2220 +
  2221 + // Allocate image
  2222 + hdu = new GFitsImageDouble(naxis, naxes);
  2223 +
  2224 + // Store data in image
  2225 + if (naxis == 2) {
  2226 + double* ptr = m_pixels;
  2227 + for (int iy = 0; iy < m_num_y; ++iy) {
  2228 + for (int ix = 0; ix < m_num_x; ++ix) {
  2229 + (*hdu)(ix,iy) = *ptr++;
  2230 + }
  2231 + }
  2232 + }
  2233 + else {
  2234 + double* ptr = m_pixels;
  2235 + for (int imap = 0; imap < m_num_maps; ++imap) {
  2236 + for (int iy = 0; iy < m_num_y; ++iy) {
  2237 + for (int ix = 0; ix < m_num_x; ++ix) {
  2238 + (*hdu)(ix,iy,imap) = *ptr++;
  2239 + }
  2240 + }
  2241 + }
  2242 + }
  2243 +
  2244 + } // endif: there were pixels
  2245 +
  2246 + // ... otherwise create an empty header
  2247 + else {
  2248 + hdu = new GFitsImageDouble;
  2249 + }
  2250 +
  2251 + // Set extension name
  2252 + hdu->extname("IMAGE");
  2253 +
  2254 + // If we have sky projection information then write into FITS header
  2255 + if (m_proj != NULL) m_proj->write(*hdu);
  2256 +
  2257 + // Set additional keywords
  2258 + //TODO
  2259 +
  2260 + // Return HDU
  2261 + return hdu;
  2262 +}
  2263 +
  2264 +/***********************************************************************//**
  2265 + * @brief publishes the skymap in a VO Hub
  2266 + *
  2267 + * @param[in]
  2268 + *
  2269 + * @exception GException::
  2270 + *
  2271 + ***************************************************************************/
  2272 +void GSkymap::publish(void)
  2273 +{
  2274 + make_votable();
  2275 + // Return
  2276 + return;
  2277 +}
  2278 +
  2279 +/***********************************************************************//**
  2280 + * @brief makes GVOTable object and fills ot with current skymap(s)
  2281 + *
  2282 + * @param[in]
  2283 + *
  2284 + * @exception GException::
  2285 + *
  2286 + ***************************************************************************/
  2287 +void GSkymap::make_votable(void)
  2288 +{
  2289 + GVOTable* m_skytable;
  2290 + m_skytable->create_votable();
  2291 + //For each pixel set the value of the pixel inside the data part
  2292 + m_skytable->fill_content("Test value");
  2293 + // Return
  2294 + return;
  2295 +}
  2296 +/*==========================================================================
  2297 + = =
  2298 + = Friends =
  2299 + = =
  2300 + ==========================================================================*/
  2301 +
  2302 +/***********************************************************************//**
  2303 + * @brief Computes square root of skymap elements
  2304 + *
  2305 + * @param[in] map Skymap.
  2306 + * @return Skymap containing the square root of every element.
  2307 + ***************************************************************************/
  2308 +GSkymap sqrt(const GSkymap& map)
  2309 +{
  2310 + // Initialise result vector
  2311 + GSkymap result(map);
  2312 +
  2313 + // Loop over all maps
  2314 + for (int i = 0; i < map.nmaps(); ++i) {
  2315 +
  2316 + // Loop over all bins
  2317 + for (int j = 0; j < map.npix(); ++j) {
  2318 +
  2319 + // Get the content from the bin
  2320 + double content = map(j,i);
  2321 +
  2322 + // Check if content is not negative
  2323 + if (content < 0.0) {
  2324 + std::string msg = "Negative value envountered."
  2325 + " Cannot take the sqrt from a negative value";
  2326 + throw GException::invalid_value(G_OP_UNARY_DIV, msg);
  2327 + }
  2328 +
  2329 + // Set content of the result map
  2330 + result(j,i) = std::sqrt(content);
  2331 +
  2332 + } // endfor: Loop over all bins
  2333 +
  2334 + } // endfor: Loop over all maps
  2335 +
  2336 + // Return vector
  2337 + return result;
  2338 +}
... ...
src/vo/GVOApp.cpp~ 0 → 100644
  1 +/***************************************************************************
  2 + * GVOApp.hpp - VO SAMP Hub class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2014 by Thierry Louge *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GVOApp.cpp
  23 + * @brief VO Application connected to SAMP HUB class implementation
  24 + * @author Thierry Louge
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#include <errno.h>
  31 +#endif
  32 +#include <cstdlib> // std::getenv() function
  33 +#include <cstdio> // std::fopen(), etc. functions
  34 +#include <cstring> // std::memset() function
  35 +#include <unistd.h> // close() function
  36 +#include "GVOApp.hpp"
  37 +#include "GException.hpp"
  38 +#include "GTools.hpp"
  39 +
  40 +/* __ Method name definitions ____________________________________________ */
  41 +
  42 +/* __ Macros _____________________________________________________________ */
  43 +
  44 +/* __ Coding definitions _________________________________________________ */
  45 +
  46 +/* __ Debug definitions __________________________________________________ */
  47 +
  48 +
  49 +/*==========================================================================
  50 + = =
  51 + = Constructors/destructors =
  52 + = =
  53 + ==========================================================================*/
  54 +
  55 +/***********************************************************************//**
  56 + * @brief Void constructor
  57 + ***************************************************************************/
  58 +GVOApp::GVOApp(void)
  59 +{
  60 + // Initialise members
  61 + init_members();
  62 +
  63 + // Return
  64 + return;
  65 +}
  66 +
  67 +
  68 +/***********************************************************************//**
  69 + * @brief Copy constructor
  70 + *
  71 + * @param[in] hub VO Hub.
  72 + ***************************************************************************/
  73 +GVOApp::GVOApp(const GVOApp& hub)
  74 +{
  75 + // Initialise members
  76 + init_members();
  77 +
  78 + // Copy members
  79 + copy_members(hub);
  80 +
  81 + // Return
  82 + return;
  83 +}
  84 +
  85 +
  86 +/***********************************************************************//**
  87 + * @brief Destructor
  88 + ***************************************************************************/
  89 +GVOApp::~GVOApp(void)
  90 +{
  91 +
  92 + // Return
  93 + return;
  94 +}
  95 +
  96 +
  97 +/*==========================================================================
  98 + = =
  99 + = Operators =
  100 + = =
  101 + ==========================================================================*/
  102 +
  103 +/***********************************************************************//**
  104 + * @brief Assignment operator
  105 + *
  106 + * @param[in] hub VO hub.
  107 + * @return VO hub.
  108 + ***************************************************************************/
  109 +GVOApp& GVOApp::operator=(const GVOApp& hub)
  110 +{
  111 + // Execute only if object is not identical
  112 + if (this != &hub) {
  113 +
  114 + // Free members
  115 + free_members();
  116 +
  117 + // Initialise members
  118 + init_members();
  119 +
  120 + // Copy members
  121 + copy_members(hub);
  122 +
  123 + } // endif: object was not identical
  124 +
  125 + // Return
  126 + return *this;
  127 +}
  128 +
  129 +
  130 +/*==========================================================================
  131 + = =
  132 + = Public methods =
  133 + = =
  134 + ==========================================================================*/
  135 +
  136 +/***********************************************************************//**
  137 + * @brief Clear object.
  138 + *
  139 + * Reset object to a clean initial state.
  140 + ***************************************************************************/
  141 +void GVOApp::clear(void)
  142 +{
  143 + // Free memory and initialise members
  144 + free_members();
  145 + init_members();
  146 +
  147 + // Return
  148 + return;
  149 +}
  150 +
  151 +
  152 +/***********************************************************************//**
  153 + * @brief Clone object
  154 + ***************************************************************************/
  155 +GVOApp* GVOApp::clone(void) const
  156 +{
  157 + // Clone client
  158 + return new GVOApp(*this);
  159 +}
  160 +
  161 +
  162 +/***********************************************************************//**
  163 + * @brief TBD
  164 + *
  165 + ***************************************************************************/
  166 +void GVOApp::start(void)
  167 +{
  168 + // Does nothing
  169 +
  170 + // Return
  171 + return;
  172 +}
  173 +
  174 +
  175 +/***********************************************************************//**
  176 + * @brief Print VO hub information
  177 + *
  178 + * @param[in] chatter Chattiness (defaults to NORMAL).
  179 + * @return String containing VO hub information
  180 + ***************************************************************************/
  181 +std::string GVOApp::print(const GChatter& chatter) const
  182 +{
  183 + // Initialise result string
  184 + std::string result;
  185 + std::list<std::string> temp;
  186 + temp = registered_calls;
  187 +
  188 + // Continue only if chatter is not silent
  189 + if (chatter != SILENT) {
  190 +
  191 + // Append header
  192 + result.append("=== GVOApp ===");
  193 + result.append(m_id);
  194 + result.append("%d",temp.size());
  195 + for (std::list<std::string>::iterator i = temp.begin(); i != temp.end(); ++i) {
  196 + result.append("Method:\n");
  197 + result.append(*i);
  198 + }
  199 +
  200 +
  201 +
  202 + } // endif: chatter was not silent
  203 +
  204 + // Return result
  205 + return result;
  206 +}
  207 +
  208 +
  209 +/*==========================================================================
  210 + = =
  211 + = Private methods =
  212 + = =
  213 + ==========================================================================*/
  214 +
  215 +/***********************************************************************//**
  216 + * @brief Initialise class members
  217 + ***************************************************************************/
  218 +void GVOApp::init_members(void)
  219 +{
  220 + // Initialise members
  221 + std::list<std::string> registeredMethods;
  222 + // Return
  223 + return;
  224 +}
  225 +
  226 +
  227 +/***********************************************************************//**
  228 + * @brief Copy class members
  229 + *
  230 + * @param[in] app registered in Hub.
  231 + ***************************************************************************/
  232 +void GVOApp::copy_members(const GVOApp& app)
  233 +{
  234 + // Copy members
  235 +
  236 +
  237 + // Return
  238 + return;
  239 +}
  240 +
  241 +
  242 +/***********************************************************************//**
  243 + * @brief Delete class members
  244 + ***************************************************************************/
  245 +void GVOApp::free_members(void)
  246 +{
  247 + // Return
  248 + return;
  249 +}
  250 +
  251 +/***********************************************************************//**
  252 + * @brief Creates nex application container
  253 + ***************************************************************************/
  254 +void GVOApp::start_app(void)
  255 +{
  256 + // Creates Hub
  257 + printf("Creating new application Container\n");
  258 +
  259 + // Return
  260 + return;
  261 +}
... ...
src/vo/GVOClient.cpp~ 0 → 100644
  1 +/***************************************************************************
  2 + * GVOClient.hpp - VO client class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2013 by Juergen Knoedlseder *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GVOClient.cpp
  23 + * @brief VO client class implementation
  24 + * @author Juergen Knoedlseder
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdlib> // std::getenv() function
  32 +#include <cstdio> // std::fopen(), etc. functions
  33 +#include <cstring> // std::memset() function
  34 +#include <unistd.h> // close() function
  35 +#include <netdb.h> // getaddrinfo() function
  36 +#include <sys/socket.h> // socket(), connect() functions
  37 +#include "GVOClient.hpp"
  38 +#include "GException.hpp"
  39 +#include "GTools.hpp"
  40 +
  41 +/* __ Method name definitions ____________________________________________ */
  42 +
  43 +/* __ Macros _____________________________________________________________ */
  44 +
  45 +/* __ Coding definitions _________________________________________________ */
  46 +
  47 +/* __ Debug definitions __________________________________________________ */
  48 +
  49 +
  50 +/*==========================================================================
  51 + = =
  52 + = Constructors/destructors =
  53 + = =
  54 + ==========================================================================*/
  55 +
  56 +/***********************************************************************//**
  57 + * @brief Void constructor
  58 + ***************************************************************************/
  59 +GVOClient::GVOClient(void)
  60 +{
  61 + // Initialise members
  62 + init_members();
  63 +
  64 + // Find Hub
  65 + find_hub();
  66 +
  67 + // Return
  68 + return;
  69 +}
  70 +
  71 +
  72 +/***********************************************************************//**
  73 + * @brief Copy constructor
  74 + *
  75 + * @param[in] client VO client.
  76 + ***************************************************************************/
  77 +GVOClient::GVOClient(const GVOClient& client)
  78 +{
  79 + // Initialise members
  80 + init_members();
  81 +
  82 + // Copy members
  83 + copy_members(client);
  84 +
  85 + // Return
  86 + return;
  87 +}
  88 +
  89 +
  90 +/***********************************************************************//**
  91 + * @brief Destructor
  92 + ***************************************************************************/
  93 +GVOClient::~GVOClient(void)
  94 +{
  95 + // Free members
  96 + free_members();
  97 +
  98 + // Return
  99 + return;
  100 +}
  101 +
  102 +
  103 +/*==========================================================================
  104 + = =
  105 + = Operators =
  106 + = =
  107 + ==========================================================================*/
  108 +
  109 +/***********************************************************************//**
  110 + * @brief Assignment operator
  111 + *
  112 + * @param[in] client VO client.
  113 + * @return VO client.
  114 + ***************************************************************************/
  115 +GVOClient& GVOClient::operator= (const GVOClient& client)
  116 +{
  117 + // Execute only if object is not identical
  118 + if (this != &client) {
  119 +
  120 + // Free members
  121 + free_members();
  122 +
  123 + // Initialise members
  124 + init_members();
  125 +
  126 + // Copy members
  127 + copy_members(client);
  128 +
  129 + } // endif: object was not identical
  130 +
  131 + // Return
  132 + return *this;
  133 +}
  134 +
  135 +
  136 +/*==========================================================================
  137 + = =
  138 + = Public methods =
  139 + = =
  140 + ==========================================================================*/
  141 +
  142 +/***********************************************************************//**
  143 + * @brief Clear object.
  144 + *
  145 + * Reset object to a clean initial state.
  146 + ***************************************************************************/
  147 +void GVOClient::clear(void)
  148 +{
  149 + // Free memory and initialise members
  150 + free_members();
  151 + init_members();
  152 +
  153 + // Return
  154 + return;
  155 +}
  156 +
  157 +
  158 +/***********************************************************************//**
  159 + * @brief Clone object
  160 + ***************************************************************************/
  161 +GVOClient* GVOClient::clone(void) const
  162 +{
  163 + // Clone client
  164 + return new GVOClient(*this);
  165 +}
  166 +
  167 +
  168 +/***********************************************************************//**
  169 + * @brief Register client to SAMP Hub
  170 + *
  171 + * Connects the VO client to the Hub. A socket to the Hub is opened and the
  172 + * client is registered at the Hub. Metadata are sent.
  173 + ***************************************************************************/
  174 +void GVOClient::connect(void)
  175 +{
  176 + // Register to Hub
  177 + printf("Sending registration to hub\n");
  178 + fflush(stdout);
  179 + register_to_hub();
  180 + printf("Registration to hub sent\n");
  181 + fflush(stdout);
  182 + // Send meta data
  183 + send_metadata();
  184 + printf("Metadata sent\n");
  185 + fflush(stdout);
  186 + // Return
  187 + return;
  188 +}
  189 +
  190 +
  191 +/***********************************************************************//**
  192 + * @brief Unregister client from SAMP Hub
  193 + *
  194 + * Disconnects the VO client from the Hub. The client is unregistered and the
  195 + * socket to the Hub is closed.
  196 + ***************************************************************************/
  197 +void GVOClient::disconnect(void)
  198 +{
  199 + // Unregister from Hub
  200 + unregister_from_hub();
  201 +
  202 + // Close socket
  203 + if (m_socket != -1) {
  204 + close(m_socket);
  205 + m_socket = -1;
  206 + }
  207 +
  208 + // Return
  209 + return;
  210 +}
  211 +
  212 +
  213 +/***********************************************************************//**
  214 + * @brief Signals if client has Hub information
  215 + *
  216 + * @return True if client has Hub information, false otherwise.
  217 + *
  218 + * Checks if all mandatory Hub tokens are non-empty.
  219 + ***************************************************************************/
  220 +bool GVOClient::has_hub(void) const
  221 +{
  222 + // Return Hub information status
  223 + return (!m_secret.empty() && !m_hub_url.empty() && !m_version.empty());
  224 +}
  225 +
  226 +
  227 +/***********************************************************************//**
  228 + * @brief Signals if client is connected to Hub
  229 + *
  230 + * @return True if client is connected to Hub, false otherwise.
  231 + *
  232 + * Checks if a client is connected to Hub.
  233 + ***************************************************************************/
  234 +bool GVOClient::is_connected(void) const
  235 +{
  236 + // Return
  237 + return false;
  238 +}
  239 +
  240 +
  241 +/***********************************************************************//**
  242 + * @brief Returns Hub response a XML object
  243 + *
  244 + * @return Hub response.
  245 + ***************************************************************************/
  246 +GXml GVOClient::response(void) const
  247 +{
  248 + // Declare empty XML document
  249 + GXml xml;
  250 +
  251 + // Continue only if connection has been established
  252 + if (m_socket != -1) {
  253 + printf("Socket identified, receive string\n");
  254 + fflush(stdout);
  255 + // Receive a string
  256 + std::string response = receive_string();
  257 +
  258 + // Find start of XML text
  259 + size_t start = response.find("<?xml");
  260 +
  261 + // If found then convert text into XML document
  262 + if (start != std::string::npos) {
  263 + xml = GXml(response.substr(start, std::string::npos));
  264 + }
  265 +
  266 + } // endif: connection has been established
  267 +
  268 + // Return XML document
  269 + printf("End of response function\n");
  270 + fflush(stdout);
  271 + return xml;
  272 +}
  273 +
  274 +
  275 +/***********************************************************************//**
  276 + * @brief Print VO client information
  277 + *
  278 + * @param[in] chatter Chattiness (defaults to NORMAL).
  279 + * @return String containing VO client information
  280 + ***************************************************************************/
  281 +std::string GVOClient::print(const GChatter& chatter) const
  282 +{
  283 + // Initialise result string
  284 + std::string result;
  285 +
  286 + // Continue only if chatter is not silent
  287 + if (chatter != SILENT) {
  288 +
  289 + // Append header
  290 + result.append("=== GVOClient ===");
  291 +
  292 + // Append client information
  293 + result.append("\n"+gammalib::parformat("Name")+m_name);
  294 +
  295 + // Append Hub information
  296 + if (has_hub()) {
  297 + result.append("\n"+gammalib::parformat("Hub key")+m_secret);
  298 + result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url);
  299 + result.append("\n"+gammalib::parformat("Hub host (port)"));
  300 + result.append(m_hub_host+" ("+m_hub_port+")");
  301 + result.append("\n"+gammalib::parformat("SAMP protocol version"));
  302 + result.append(m_version);
  303 + result.append("\n"+gammalib::parformat("Hub connection"));
  304 + if (m_socket == -1) {
  305 + result.append("no");
  306 + }
  307 + else {
  308 + if (!m_client_key.empty()) {
  309 + result.append("registered as \""+m_client_id);
  310 + result.append("\" on Hub \""+m_hub_id);
  311 + result.append("\" via socket "+gammalib::str(m_socket));
  312 + }
  313 + else {
  314 + result.append("established on socket ");
  315 + result.append(gammalib::str(m_socket));
  316 + }
  317 + }
  318 + }
  319 + else {
  320 + result.append("\n"+gammalib::parformat("Hub key"));
  321 + result.append("No Hub has been found");
  322 + }
  323 +
  324 + } // endif: chatter was not silent
  325 +
  326 + // Return result
  327 + return result;
  328 +}
  329 +
  330 +
  331 +/*==========================================================================
  332 + = =
  333 + = Private methods =
  334 + = =
  335 + ==========================================================================*/
  336 +
  337 +/***********************************************************************//**
  338 + * @brief Initialise class members
  339 + ***************************************************************************/
  340 +void GVOClient::init_members(void)
  341 +{
  342 + // Initialise members
  343 + m_name = "GammaLib";
  344 + m_secret.clear();
  345 + m_hub_url.clear();
  346 + m_hub_host.clear();
  347 + m_hub_port.clear();
  348 + m_version.clear();
  349 + m_client_key.clear();
  350 + m_hub_id.clear();
  351 + m_client_id.clear();
  352 + m_socket = -1; // Signals no socket
  353 +
  354 + // Return
  355 + return;
  356 +}
  357 +
  358 +
  359 +/***********************************************************************//**
  360 + * @brief Copy class members
  361 + *
  362 + * @param[in] client VO client.
  363 + ***************************************************************************/
  364 +void GVOClient::copy_members(const GVOClient& client)
  365 +{
  366 + // Copy members
  367 + m_name = client.m_name;
  368 + m_secret = client.m_secret;
  369 + m_hub_url = client.m_hub_url;
  370 + m_hub_host = client.m_hub_host;
  371 + m_hub_port = client.m_hub_port;
  372 + m_version = client.m_version;
  373 + m_client_key = client.m_client_key;
  374 + m_hub_id = client.m_hub_id;
  375 + m_client_id = client.m_client_id;
  376 + m_socket = client.m_socket;
  377 +
  378 + // Return
  379 + return;
  380 +}
  381 +
  382 +
  383 +/***********************************************************************//**
  384 + * @brief Delete class members
  385 + ***************************************************************************/
  386 +void GVOClient::free_members(void)
  387 +{
  388 + // Unregister from Hub
  389 + unregister_from_hub();
  390 +
  391 + // Close socket
  392 + if (m_socket != -1) {
  393 + close(m_socket);
  394 + m_socket = -1;
  395 + }
  396 +
  397 + // Return
  398 + return;
  399 +}
  400 +
  401 +
  402 +/***********************************************************************//**
  403 + * @brief Find SAMP Hub
  404 + *
  405 + * @return True of SAMP Hub has been found, false otherwise.
  406 + *
  407 + * Search a valid SAMP Hub and retrieve all mandatory token for this Hub.
  408 + * The manadtory tokens are
  409 + *
  410 + * samp.secret Opaque text string required for Hub registration
  411 + * samp.hub.xmlrpc.url XML-RPC endpoint for communication
  412 + * samp.profile.version Version of SAMP profile
  413 + *
  414 + * Implements IVOA standard REC-SAMP-1.3-20120411.
  415 + *
  416 + * @todo If no valid Hub was found the method should attempt to start its
  417 + * own Hub.
  418 + ***************************************************************************/
  419 +bool GVOClient::find_hub(void)
  420 +{
  421 + // Allocate line buffer
  422 + const int n = 1000;
  423 + char line[n];
  424 +
  425 + // Initialise find flag to false
  426 + bool found = false;
  427 +
  428 + // Get lockfile URL
  429 + std::string lockurl = get_hub_lockfile();
  430 +
  431 + // Continue only if a URL has been found
  432 + if (!lockurl.empty()) {
  433 +
  434 + // If we have a file:// prefix then strip it now. This is a kluge
  435 + // and should be remplaced by a method that allows opening any kind
  436 + // of URL
  437 + if (lockurl.compare(0, 7, "file://") == 0) {
  438 + lockurl = lockurl.substr(7, std::string::npos);
  439 + }
  440 +
  441 + // Open SAMP lockfile. Continue only if opening was successful
  442 + FILE* fptr = fopen(lockurl.c_str(), "r");
  443 + if (fptr != NULL) {
  444 +
  445 + // Parse lockfile and search for mandatory tokens
  446 + while (fgets(line, n, fptr) != NULL) {
  447 +
  448 + // Convert line to C++ string
  449 + std::string cline = std::string(line);
  450 +
  451 + // Check for secret key
  452 + if (cline.compare(0, 12, "samp.secret=") == 0) {
  453 + m_secret = gammalib::strip_chars(cline.substr(12, std::string::npos), "\r\n");
  454 + }
  455 +
  456 + // Check for Hub URL
  457 + else if (cline.compare(0, 20, "samp.hub.xmlrpc.url=") == 0) {
  458 + m_hub_url = gammalib::strip_chars(cline.substr(20, std::string::npos), "\r\n");
  459 + }
  460 +
  461 + // Check for profile version
  462 + else if (cline.compare(0, 21, "samp.profile.version=") == 0) {
  463 + m_version = gammalib::strip_chars(cline.substr(21, std::string::npos), "\r\n");
  464 + }
  465 +
  466 + }
  467 +
  468 + // Close SAMP lockfile
  469 + fclose(fptr);
  470 +
  471 + // Extract host and port from Hub URL
  472 + if (m_hub_url.compare(0, 7, "http://") == 0) {
  473 + size_t length;
  474 + size_t start = 7;
  475 + size_t stop = m_hub_url.find(":", start);
  476 + if (stop != std::string::npos) {
  477 + length = stop - start;
  478 + }
  479 + else {
  480 + length = std::string::npos;
  481 + }
  482 + m_hub_host = m_hub_url.substr(start, length);
  483 + if (stop != std::string::npos) {
  484 + stop = stop + 1;
  485 + size_t end = m_hub_url.find("/", stop);
  486 + if (end != std::string::npos) {
  487 + length = end - stop;
  488 + }
  489 + else {
  490 + length = std::string::npos;
  491 + }
  492 + m_hub_port = m_hub_url.substr(stop, length);
  493 + }
  494 + }
  495 +
  496 + // Check for existence of mandatory tokens
  497 + found = has_hub();
  498 +
  499 + } // endif: SAMP lockfile opened
  500 +
  501 + } // endif: URL has been found
  502 +
  503 + //TODO: Create GammaLib own Hub in case that no Hub has been found
  504 + //if (!found) {
  505 + //}
  506 +
  507 + // If no Hub has been found, clear all Hub related members
  508 + if (!found) {
  509 + m_secret.clear();
  510 + m_hub_url.clear();
  511 + m_version.clear();
  512 + }
  513 +
  514 + // Return find flag
  515 + return found;
  516 +}
  517 +
  518 +
  519 +/***********************************************************************//**
  520 + * @brief Connect to SAMP Hub
  521 + *
  522 + * Connects to Hub by creating a socket and connecting to this socket. The
  523 + * method expects that a Hub has already been found. If no Hub has been found
  524 + * (i.e. has_hub() returns false), the method does nothing.
  525 + *
  526 + * The method extracts the hostname and the port from the Hub endpoint URL.
  527 + * If Hub connection fails, any created socket is closed.
  528 + *
  529 + * If the method is successful, m_socket will contain on exit a non-negative
  530 + * number. If any failure occurs, m_socket will be set to -1.
  531 + ***************************************************************************/
  532 +void GVOClient::connect_to_hub(void)
  533 +{
  534 + // Close any existing socket
  535 + if (m_socket != -1) {
  536 + close(m_socket);
  537 + m_socket = -1;
  538 + }
  539 +
  540 + // Continue only if host and port information was found
  541 + if (!m_hub_host.empty() && !m_hub_port.empty()) {
  542 +
  543 + // Set hints
  544 + struct addrinfo hints;
  545 + std::memset(&hints, 0, sizeof(hints));
  546 + hints.ai_family = AF_INET;
  547 + hints.ai_socktype = SOCK_STREAM;
  548 +
  549 + // Get server information
  550 + struct addrinfo* servinfo;
  551 + if (getaddrinfo(m_hub_host.c_str(), m_hub_port.c_str(),
  552 + &hints, &servinfo) == 0) {
  553 +
  554 + // Loop through all the results and connect to the first
  555 + // we can
  556 + for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) {
  557 +
  558 + // Create socket
  559 + m_socket = socket(ptr->ai_family,
  560 + ptr->ai_socktype,
  561 + ptr->ai_protocol);
  562 +
  563 + // Connect to socket if socket is valid
  564 + if (m_socket != -1) {
  565 + if (::connect(m_socket,
  566 + ptr->ai_addr,
  567 + ptr->ai_addrlen) == -1) {
  568 + close(m_socket);
  569 + m_socket = -1;
  570 + }
  571 + }
  572 +
  573 + } // endfor: looped through all results
  574 +
  575 + } // endif: server information was valid
  576 +
  577 + } // endif: host and port information found
  578 +
  579 + // Return
  580 + return;
  581 +}
  582 +
  583 +
  584 +/***********************************************************************//**
  585 + * @brief Register client at SAMP Hub
  586 + ***************************************************************************/
  587 +void GVOClient::register_to_hub(void)
  588 +{
  589 + // Connect to Hub
  590 + connect_to_hub();
  591 +
  592 + // Continue only if Hub connection has been established
  593 + if (m_socket != -1) {
  594 +
  595 + // Declare message
  596 + std::string msg = "";
  597 +
  598 + // Set metadata header
  599 + msg.append("<?xml version=\"1.0\"?>\n");
  600 + msg.append("<methodCall>\n");
  601 + msg.append("<methodName>samp.hub.register</methodName>\n");
  602 + msg.append("<params>\n");
  603 + msg.append("<param><value><string>"+m_secret+"</string></value></param>\n");
  604 + msg.append("</params>\n");
  605 + msg.append("</methodCall>\n");
  606 +
  607 + // Post message
  608 + post_string(msg);
  609 + printf("Waiting for Hub response\n");
  610 + fflush(stdout);
  611 + // Get Hub response
  612 + GXml xml = response();
  613 +
  614 + printf("Hub response received");
  615 + fflush(stdout);
  616 +
  617 + // Extract Hub and client identifiers
  618 + m_client_key = get_response_value(xml, "samp.private-key");
  619 + m_hub_id = get_response_value(xml, "samp.hub-id");
  620 + m_client_id = get_response_value(xml, "samp.self-id");
  621 +
  622 + } // endif: Hub connection has been established
  623 +
  624 + // Return
  625 + return;
  626 +}
  627 +
  628 +
  629 +/***********************************************************************//**
  630 + * @brief Unregister client from SAMP Hub
  631 + ***************************************************************************/
  632 +void GVOClient::unregister_from_hub(void)
  633 +{
  634 + // Connect to Hub
  635 + connect_to_hub();
  636 +
  637 + // Continue only if Hub connection has been established
  638 + if (m_socket != -1) {
  639 +
  640 + // Declare message
  641 + std::string msg = "";
  642 +
  643 + // Set metadata header
  644 + msg.append("<?xml version=\"1.0\"?>\n");
  645 + msg.append("<methodCall>\n");
  646 + msg.append("<methodName>samp.hub.unregister</methodName>\n");
  647 + msg.append("<params>\n");
  648 + msg.append("<param><value><string>"+m_client_key+"</string></value></param>\n");
  649 + msg.append("</params>\n");
  650 + msg.append("</methodCall>\n");
  651 +
  652 + // Post message
  653 + post_string(msg);
  654 +
  655 + // Get Hub response
  656 + GXml xml = response();
  657 +
  658 + // Reset Hub and client identifiers
  659 + m_client_key.clear();
  660 + m_hub_id.clear();
  661 + m_client_id.clear();
  662 +
  663 + } // endif: Hub connection has been established
  664 +
  665 + // Return
  666 + return;
  667 +}
  668 +
  669 +
  670 +/***********************************************************************//**
  671 + * @brief Send client metadata to Hub
  672 + ***************************************************************************/
  673 +void GVOClient::send_metadata(void)
  674 +{
  675 + // Connect to Hub. This was needed to post the metadata to the Hub.
  676 + // Apparently, the connection is lost after each write/read cycle.
  677 + // Maybe this is socket standard?
  678 + connect_to_hub();
  679 +
  680 + printf("send metadata function \n");
  681 + fflush(stdout);
  682 + // Continue only if Hub connection has been established
  683 + if (m_socket != -1) {
  684 +
  685 + // Declare message
  686 + std::string msg = "";
  687 +
  688 + // Set metadata header
  689 + msg.append("<?xml version=\"1.0\"?>\n");
  690 + msg.append("<methodCall>\n");
  691 + msg.append("<methodName>samp.hub.declareMetadata</methodName>\n");
  692 + msg.append("<params>\n");
  693 + msg.append("<param><value><string>"+m_client_key+"</string></value></param>\n");
  694 + msg.append("<param><value><struct>\n");
  695 +
  696 + // Set SAMP name
  697 + msg.append("<member>\n");
  698 + msg.append("<name>samp.name</name>\n");
  699 + msg.append("<value><string>"+m_name+"</string></value>\n");
  700 + msg.append("</member>\n");
  701 +
  702 + // Set SAMP description text
  703 + msg.append("<member>\n");
  704 + msg.append("<name>samp.description.text</name>\n");
  705 + msg.append("<value><string>GammaLib client</string></value>\n");
  706 + msg.append("</member>\n");
  707 +
  708 + // Set SAMP icon URL
  709 + msg.append("<member>\n");
  710 + msg.append("<name>samp.icon.url</name>\n");
  711 + msg.append("<value><string>http://a.fsdn.com/allura/p/gammalib/icon</string></value>\n");
  712 + msg.append("</member>\n");
  713 +
  714 + // Set author affiliation
  715 + msg.append("<member>\n");
  716 + msg.append("<name>author.affiliation</name>\n");
  717 + msg.append("<value><string>IRAP, Toulouse, France</string></value>\n");
  718 + msg.append("</member>\n");
  719 +
  720 + // Set author e-mail
  721 + msg.append("<member>\n");
  722 + msg.append("<name>author.email</name>\n");
  723 + msg.append("<value><string>jurgen.knodlseder@irap.omp.eu</string></value>\n");
  724 + msg.append("</member>\n");
  725 +
  726 + // Set author name
  727 + msg.append("<member>\n");
  728 + msg.append("<name>author.name</name>\n");
  729 + msg.append("<value><string>Juergen Knoedlseder</string></value>\n");
  730 + msg.append("</member>\n");
  731 +
  732 + // Set metadata trailer
  733 + msg.append("</struct></value></param>\n");
  734 + msg.append("</params>\n");
  735 + msg.append("</methodCall>\n");
  736 +
  737 + // Post message
  738 + post_string(msg);
  739 +
  740 + // Get Hub response
  741 + GXml xml = response();
  742 +
  743 + } // endif: Hub connection has been established
  744 +
  745 + // Return
  746 + return;
  747 +}
  748 +
  749 +
  750 +/***********************************************************************//**
  751 + * @brief Returns value for a SAMP Hub response parameter
  752 + *
  753 + * @param[in] xml Hub response XML document.
  754 + * @param[in] name Parameter name.
  755 + * @return Parameter value.
  756 + *
  757 + * Returns value for a SAMP Hub response parameter. If the specified
  758 + * parameter was not found or if the response structure is not compliant,
  759 + * an empty string is returned.
  760 + ***************************************************************************/
  761 +std::string GVOClient::get_response_value(const GXml& xml,
  762 + const std::string& name) const
  763 +{
  764 + // Declare value
  765 + std::string value = "";
  766 +
  767 + // Search for value of specified member
  768 + const GXmlNode* node = xml.element("methodResponse", 0);
  769 + if (node != NULL) {
  770 + node = node->element("params", 0);
  771 + if (node != NULL) {
  772 + node = node->element("param", 0);
  773 + if (node != NULL) {
  774 + node = node->element("value", 0);
  775 + if (node != NULL) {
  776 + node = node->element("struct", 0);
  777 + if (node != NULL) {
  778 + int num = node->elements("member");
  779 + for (int i = 0; i < num; ++i) {
  780 + const GXmlNode* member = node->element("member", i);
  781 + std::string one_name;
  782 + std::string one_value;
  783 + get_name_value_pair(member, one_name, one_value);
  784 + if (one_name == name) {
  785 + value = one_value;
  786 + break;
  787 + }
  788 + }
  789 + }
  790 + }
  791 + }
  792 + }
  793 + }
  794 +
  795 + // Return value
  796 + return value;
  797 +}
  798 +
  799 +
  800 +/***********************************************************************//**
  801 + * @brief Extract name / value pair from XML node
  802 + *
  803 + * @param[in] node Pointer to XML node.
  804 + * @param[out] name Name string.
  805 + * @param[out] value Value string.
  806 + *
  807 + * Extracts a name / value pair from a XML node. If the XML node pointer is
  808 + * NULL, the name and value strings will be empty.
  809 + ***************************************************************************/
  810 +void GVOClient::get_name_value_pair(const GXmlNode* node,
  811 + std::string& name,
  812 + std::string& value) const
  813 +{
  814 + // Clear name and value strings
  815 + name.clear();
  816 + value.clear();
  817 +
  818 + // Continue only if node is valid
  819 + if (node != NULL) {
  820 +
  821 + // Get name node and extract text content
  822 + const GXmlNode* ptr = node->element("name", 0);
  823 + if (ptr != NULL) {
  824 + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]);
  825 + if (text != NULL) {
  826 + name = text->text();
  827 + }
  828 + }
  829 +
  830 + // Get value node and extract text content
  831 + ptr = node->element("value", 0);
  832 + if (ptr != NULL) {
  833 + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]);
  834 + if (text != NULL) {
  835 + value = text->text();
  836 + }
  837 + }
  838 + }
  839 +
  840 + // Return
  841 + return;
  842 +}
  843 +
  844 +
  845 +/***********************************************************************//**
  846 + * @brief Post string content to Hub
  847 + *
  848 + * @param[in] content String content to post
  849 + *
  850 + * Posts the content of a string to the Hub.
  851 + *
  852 + * The method does nothing if no Hub connection has been established.
  853 + ***************************************************************************/
  854 +void GVOClient::post_string(const std::string& content) const
  855 +{
  856 + // Continue only if Hub connection has been established
  857 + if (m_socket != -1) {
  858 +
  859 + // Determine content length
  860 + int length = content.length();
  861 +
  862 + // Set prefix
  863 + std::string prefix = "POST /xmlrpc-1 HTTP/1.0\n"
  864 + "User-Agent: GammaLib\n"
  865 + "Content-Type: text/xml\n"
  866 + "Content-Length: "+gammalib::str(length)+"\n\n";
  867 +
  868 + // Build post string
  869 + std::string post = prefix + content;
  870 +
  871 + // Send content to socket
  872 + bool done = false;
  873 + do {
  874 + int length = post.length();
  875 + int sent_length = send(m_socket, post.c_str(), length, 0);
  876 + if (sent_length < length) {
  877 + post = post.substr(sent_length, std::string::npos);
  878 + }
  879 + else {
  880 + done = true;
  881 + }
  882 + } while (!done);
  883 +
  884 + } // endif: Hub connection had been established
  885 +
  886 + // Return
  887 + return;
  888 +}
  889 +
  890 +
  891 +/***********************************************************************//**
  892 + * @brief Receive string content from Hub
  893 + *
  894 + * @return String received from Hub.
  895 + *
  896 + * Reads information sent by Hub into a string.
  897 + *
  898 + * The method does nothing if no Hub connection has been established.
  899 + ***************************************************************************/
  900 +std::string GVOClient::receive_string(void) const
  901 +{
  902 + // Initialise empty string
  903 + std::string result = "";
  904 +
  905 + // Continue only if Hub connection has been established
  906 + if (m_socket != -1) {
  907 +
  908 + // Define buffer
  909 + char buffer[1001];
  910 +
  911 + // Read buffer until it is empty
  912 + int n = 0;
  913 + //do {
  914 + printf("receive socket instruction\n");
  915 + fflush(stdout);
  916 + n = recv(m_socket, buffer, 1000, 0);
  917 + printf("data received: %s\n",buffer);
  918 + fflush(stdout);
  919 + if (n > 0) {
  920 + buffer[n+1] = '\0';
  921 + result.append(std::string(buffer));
  922 + }
  923 + //} while (n > 0);
  924 +
  925 + } // endif: Hub connection had been established
  926 +
  927 + // Return result
  928 + return result;
  929 +}
  930 +
  931 +
  932 +/***********************************************************************//**
  933 + * @brief Returns SAMP Hub lockfile URL
  934 + *
  935 + * @return SAMP Hub lockfile URL (empty if no lockfile was found).
  936 + *
  937 + * Implements IVOA standard REC-SAMP-1.3-20120411.
  938 + ***************************************************************************/
  939 +std::string GVOClient::get_hub_lockfile(void) const
  940 +{
  941 + // Initialise result
  942 + std::string url = "";
  943 +
  944 + // Check for existence of the SAMP_HUB environment variable first
  945 + char* hub_ptr = std::getenv("SAMP_HUB");
  946 + if (hub_ptr != NULL) {
  947 +
  948 + // Check for mandatory std-lockurl: prefix (no other prefixe is
  949 + // supported so far)
  950 + std::string lockurl = std::string(hub_ptr);
  951 + if (lockurl.compare(0, 12, "std-lockurl:") == 0) {
  952 +
  953 + // Extract URL
  954 + url = lockurl.substr(12, std::string::npos);
  955 +
  956 + } // endif: std-lockurl: prefix found
  957 +
  958 + }
  959 +
  960 + // ... otherwise the lockfile should be $HOME/.samp
  961 + else {
  962 +
  963 + // Get user's HOME directory path as the prefix of the full
  964 + // path. If the HOME environment variable is not set we
  965 + // expect that .samp is in the local directory. This is non
  966 + // standard, but prevents for creating an exception here.
  967 + std::string prefix = "";
  968 + char* home_ptr = std::getenv("HOME");
  969 + if (home_ptr != NULL) {
  970 + prefix = std::string(home_ptr) + "/";
  971 + }
  972 +
  973 + // Set filename
  974 + url = prefix + ".samp";
  975 +
  976 + } // endelse: no SAMP_HUB environment variable found
  977 +
  978 + // Return URL
  979 + return url;
  980 +}
... ...
src/vo/GVOHub.cpp
... ... @@ -488,7 +488,7 @@ void GVOHub::handle_request(const socklen_t&amp; sock)
488 488 request_ping(sock);
489 489 }
490 490 else if (method_called.compare("samp.hub.call") == 0) {
491   - request_ping(sock);
  491 + request_call(xml,sock);
492 492 }
493 493 else if (method_called.compare("samp.hub.callAll") == 0) {
494 494 request_ping(sock);
... ... @@ -904,9 +904,8 @@ void GVOHub::request_get_registered_clients(const GXml&amp; xml, const socklen_t&amp; so
904 904  
905 905 // Declare message
906 906 std::string msg = "";
907   -
908 907 // Set response
909   - msg.append("<?xml version=\'1.0\' encoding=\"UTF-8\"?>\n");
  908 + msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
910 909 msg.append("<methodResponse>\n");
911 910 msg.append("<params>\n");
912 911 msg.append(" <param><value><array><data>\n");
... ... @@ -925,7 +924,6 @@ void GVOHub::request_get_registered_clients(const GXml&amp; xml, const socklen_t&amp; so
925 924 msg.append(" </data></array></value></param>\n");
926 925 msg.append("</params>\n");
927 926 msg.append("</methodResponse>\n");
928   -
929 927 // Post response
930 928 post_string(msg, sock);
931 929  
... ... @@ -950,6 +948,14 @@ void GVOHub::request_get_subscribed_clients(const GXml&amp; xml, const socklen_t&amp; so
950 948 std::cout << "GVOHub::request_get_subscribed_clients" << std::endl;
951 949 #endif
952 950  
  951 + // Declare message
  952 + std::string msg = "";
  953 +
  954 + msg.append("<?xml version=\'1.0\' encoding=\"UTF-8\"?>\n");
  955 + msg.append("<methodResponse>\n");
  956 + msg.append("<params>\n");
  957 + msg.append(" <param><value><struct><member><name>c0</name><value><struct></struct></value></member><member><name>gammalib_hub</name><value><struct></struct></value></member></struct></value></param></params></methodResponse>");
  958 +
953 959 /*
954 960 std::string buffer;
955 961 const int n = 1000;
... ... @@ -971,8 +977,10 @@ void GVOHub::request_get_subscribed_clients(const GXml&amp; xml, const socklen_t&amp; so
971 977 fclose(fptr);
972 978 */
973 979  
  980 + // Post response
  981 + post_string(msg, sock);
974 982 // Post void message
975   - post_samp_void(sock);
  983 + //post_samp_void(sock);
976 984  
977 985 // Return
978 986 return;
... ... @@ -1114,6 +1122,77 @@ void GVOHub::request_get_metadata(const GXml&amp; xml, const socklen_t&amp; sock)
1114 1122 return;
1115 1123 }
1116 1124  
  1125 +/***********************************************************************//**
  1126 + * @brief Handles calls to specific client
  1127 + *
  1128 + * @param[in] xml XML message sent by client.
  1129 + * @param[in] sock Socket.
  1130 + *
  1131 + * Handles all incoming cals for a specific client
  1132 + ***************************************************************************/
  1133 +void GVOHub::request_call(const GXml& xml, const socklen_t& sock)
  1134 +{
  1135 + // Header
  1136 + #if defined(G_CONSOLE_DUMP)
  1137 + std::cout << "GVOHub::request_get_registered_clients" << std::endl;
  1138 + #endif
  1139 +
  1140 + // Get client key
  1141 + std::string key = get_client_key(xml);
  1142 + // Get message mtype
  1143 + std::string mtype = get_mtype(xml);
  1144 + // Get the key of client who is to be contacted with the message
  1145 + // Declare message
  1146 + std::string msg = "";
  1147 + // Determine which call has been invoqued
  1148 + // Loop over all clients and send notification
  1149 + for (int i = 0; i < m_clients.size(); ++i) {
  1150 + msg = "";
  1151 +
  1152 + // Set response for table.load.votable
  1153 + msg.append("<?xml version=\"1.0\"?>\n");
  1154 + msg.append("<methodCall><methodName>samp.client.receiveCall</methodName>\n");
  1155 + msg.append("<params>\n");
  1156 + msg.append(" <param><value>");
  1157 + msg.append(m_clients[i].private_key);
  1158 + msg.append("</value></param>\n");
  1159 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1160 + msg.append(" <param><value><struct>\n");
  1161 + msg.append(" <member>\n");
  1162 + msg.append(" <name>samp.mtype</name>\n");
  1163 + msg.append(" <value>table.load.votable</value>\n");
  1164 + msg.append(" </member>\n");
  1165 + msg.append(" <member>\n");
  1166 + msg.append(" <name>samp.params</name>\n");
  1167 + msg.append(" <value><struct>\n");
  1168 + msg.append(" <member>\n");
  1169 + msg.append(" <name>name</name>\n");
  1170 + msg.append(" <value>imagename</value>\n");
  1171 + msg.append(" </member>\n");
  1172 + msg.append(" <member>\n");
  1173 + msg.append(" <name>table-id</name>\n");
  1174 + msg.append(" <value>id of table</value>\n");
  1175 + msg.append(" </member>\n");
  1176 + msg.append(" <member>\n");
  1177 + msg.append(" <name>url</name>\n");
  1178 + msg.append(" <value>url to the table</value>\n");
  1179 + msg.append(" </member>\n");
  1180 + msg.append(" </struct></value>\n");
  1181 + msg.append(" </member>\n");
  1182 + msg.append(" </struct></value>\n");
  1183 + msg.append(" </param>\n");
  1184 + msg.append("</params>\n");
  1185 + msg.append("</methodCall>\n");
  1186 +
  1187 +
  1188 + // Post notification
  1189 + notify(m_clients[i].url, msg);
  1190 + }
  1191 +
  1192 + // Return
  1193 + return;
  1194 +
  1195 +}
1117 1196  
1118 1197 /***********************************************************************//**
1119 1198 * @brief Handles Hub shutdown requests
... ... @@ -1947,4 +2026,61 @@ std::string GVOHub::random_string(const size_t&amp; length) const
1947 2026 // Return string
1948 2027 return str;
1949 2028 }
  2029 +/***********************************************************************//**
  2030 + * @brief Extract mtype from XML request
  2031 + *
  2032 + * @param[in] xml XML message sent by client.
  2033 + *
  2034 + * Extracts the mtype identifying calling message from the XML request.
  2035 + ***************************************************************************/
  2036 +std::string GVOHub::get_mtype(const GXml& xml) const
  2037 +{
  2038 + // Header
  2039 + #if defined(G_CONSOLE_DUMP)
  2040 + std::cout << "GVOHub::get_mtype" << std::endl;
  2041 + #endif
  2042 +
  2043 + // Initialise response
  2044 + std::string client_key = "";
  2045 +
  2046 + // Get the client's private key
  2047 + const GXmlNode* node = xml.element("methodCall > params > param > value");
  2048 + if (node != NULL) {
  2049 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  2050 + if (text != NULL) {
  2051 + client_key = text->text();
  2052 + }
  2053 + }
  2054 +
  2055 + // Return key
  2056 + return client_key;
  2057 +}
  2058 +/***********************************************************************//**
  2059 + * @brief Extract client destination from XML request
  2060 + *
  2061 + * @param[in] xml XML message sent by client.
  2062 + *
  2063 + * Extracts identifier of destination client from the XML request.
  2064 + ***************************************************************************/
  2065 +std::string GVOHub::get_destination(const GXml& xml) const
  2066 +{
  2067 + // Header
  2068 + #if defined(G_CONSOLE_DUMP)
  2069 + std::cout << "GVOHub::get_mtype" << std::endl;
  2070 + #endif
1950 2071  
  2072 + // Initialise response
  2073 + std::string client_key = "";
  2074 +
  2075 + // Get the client's private key
  2076 + const GXmlNode* node = xml.element("methodCall > params > param > value");
  2077 + if (node != NULL) {
  2078 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  2079 + if (text != NULL) {
  2080 + client_key = text->text();
  2081 + }
  2082 + }
  2083 +
  2084 + // Return key
  2085 + return client_key;
  2086 +}
... ...
src/vo/GVOHub.cpp~ 0 → 100644
  1 +/***************************************************************************
  2 + * GVOHub.cpp - VO SAMP Hub class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2014-2015 by Thierry Louge *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GVOHub.cpp
  23 + * @brief VO SAMP Hub class implementation
  24 + * @author Thierry Louge
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdlib> // std::getenv() function
  32 +#include <cstdio> // std::fopen(), etc. functions
  33 +#include <cstring> // std::memset() function
  34 +#include <csignal> // signal() function
  35 +#include <cerrno> // errno
  36 +#include <unistd.h> // close() function
  37 +#include <netdb.h> // getaddrinfo() function
  38 +#include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons
  39 +#include <fstream>
  40 +#include <sys/shm.h>
  41 +#include <sys/socket.h> // socket(), connect() functions
  42 +#include <sys/wait.h> // waitpid() function
  43 +#include <arpa/inet.h> // inet_addr() function
  44 +#include "GVOHub.hpp"
  45 +#include "GException.hpp"
  46 +#include "GTools.hpp"
  47 +
  48 +/* __ Method name definitions ____________________________________________ */
  49 +#define G_START_HUB "GVOHub::start_hub()"
  50 +
  51 +/* __ Macros _____________________________________________________________ */
  52 +
  53 +/* __ Coding definitions _________________________________________________ */
  54 +
  55 +/* __ Debug definitions __________________________________________________ */
  56 +//#define G_CONSOLE_DUMP
  57 +#define G_SHOW_MESSAGE
  58 +
  59 +
  60 +/*==========================================================================
  61 + = =
  62 + = Constructors/destructors =
  63 + = =
  64 + ==========================================================================*/
  65 +
  66 +/***********************************************************************//**
  67 + * @brief Void constructor
  68 + ***************************************************************************/
  69 +GVOHub::GVOHub(void)
  70 +{
  71 + // Initialise members
  72 + init_members();
  73 +
  74 + // Return
  75 + return;
  76 +}
  77 +
  78 +
  79 +/***********************************************************************//**
  80 + * @brief Copy constructor
  81 + *
  82 + * @param[in] hub VO Hub.
  83 + ***************************************************************************/
  84 +GVOHub::GVOHub(const GVOHub& hub)
  85 +{
  86 + // Initialise members
  87 + init_members();
  88 +
  89 + // Copy members
  90 + copy_members(hub);
  91 +
  92 + // Return
  93 + return;
  94 +}
  95 +
  96 +
  97 +/***********************************************************************//**
  98 + * @brief Destructor
  99 + ***************************************************************************/
  100 +GVOHub::~GVOHub(void)
  101 +{
  102 + // Free members
  103 + free_members();
  104 +
  105 + // Return
  106 + return;
  107 +}
  108 +
  109 +
  110 +/*==========================================================================
  111 + = =
  112 + = Operators =
  113 + = =
  114 + ==========================================================================*/
  115 +
  116 +/***********************************************************************//**
  117 + * @brief Assignment operator
  118 + *
  119 + * @param[in] hub VO hub.
  120 + * @return VO hub.
  121 + ***************************************************************************/
  122 +GVOHub& GVOHub::operator=(const GVOHub& hub)
  123 +{
  124 + // Execute only if object is not identical
  125 + if (this != &hub) {
  126 +
  127 + // Free members
  128 + free_members();
  129 +
  130 + // Initialise members
  131 + init_members();
  132 +
  133 + // Copy members
  134 + copy_members(hub);
  135 +
  136 + } // endif: object was not identical
  137 +
  138 + // Return
  139 + return *this;
  140 +}
  141 +
  142 +
  143 +/*==========================================================================
  144 + = =
  145 + = Public methods =
  146 + = =
  147 + ==========================================================================*/
  148 +
  149 +/***********************************************************************//**
  150 + * @brief Clear object.
  151 + *
  152 + * Reset object to a clean initial state.
  153 + ***************************************************************************/
  154 +void GVOHub::clear(void)
  155 +{
  156 + // Free members
  157 + free_members();
  158 +
  159 + // Initialise members
  160 + init_members();
  161 +
  162 + // Return
  163 + return;
  164 +}
  165 +
  166 +
  167 +/***********************************************************************//**
  168 + * @brief Clone object
  169 + ***************************************************************************/
  170 +GVOHub* GVOHub::clone(void) const
  171 +{
  172 + // Clone client
  173 + return new GVOHub(*this);
  174 +}
  175 +
  176 +
  177 +/***********************************************************************//**
  178 + * @brief Start Hub
  179 + ***************************************************************************/
  180 +void GVOHub::start(void)
  181 +{
  182 + // Create SAMP file
  183 + create_samp_file();
  184 +
  185 + // Start Hub
  186 + start_hub();
  187 +
  188 + // Return
  189 + return;
  190 +}
  191 +
  192 +
  193 +/***********************************************************************//**
  194 + * @brief Print VO hub information
  195 + *
  196 + * @param[in] chatter Chattiness (defaults to NORMAL).
  197 + * @return String containing VO hub information
  198 + ***************************************************************************/
  199 +std::string GVOHub::print(const GChatter& chatter) const
  200 +{
  201 + // Initialise result string
  202 + std::string result;
  203 +
  204 + // Continue only if chatter is not silent
  205 + if (chatter != SILENT) {
  206 +
  207 + // Append header
  208 + result.append("=== GVOHub ===");
  209 +
  210 + // Append Hub information
  211 + result.append("\n"+gammalib::parformat("Hub identifier")+m_hub_id);
  212 + result.append("\n"+gammalib::parformat("Hub key")+m_secret);
  213 + result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url);
  214 + result.append("\n"+gammalib::parformat("Hub host")+m_hub_host);
  215 + result.append("\n"+gammalib::parformat("Hub port")+m_hub_port);
  216 + result.append("\n"+gammalib::parformat("Hub path")+m_hub_path);
  217 + result.append("\n"+gammalib::parformat("SAMP protocol version"));
  218 + result.append(m_version);
  219 +
  220 + } // endif: chatter was not silent
  221 +
  222 + // Return result
  223 + return result;
  224 +}
  225 +
  226 +
  227 +/*==========================================================================
  228 + = =
  229 + = Private methods =
  230 + = =
  231 + ==========================================================================*/
  232 +
  233 +/***********************************************************************//**
  234 + * @brief Initialise class members
  235 + ***************************************************************************/
  236 +void GVOHub::init_members(void)
  237 +{
  238 + // Initialise members
  239 + m_secret = random_string(15);
  240 + m_hub_host = "127.0.0.1";
  241 + m_hub_port = "2526";
  242 + m_hub_path = "xmlrpc";
  243 + m_hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path;
  244 + m_version = "1.3";
  245 + m_hub_id = "gammalib_hub";
  246 + m_socket = -1; // Signals no socket
  247 + m_shutdown = false;
  248 + m_clients.clear();
  249 +
  250 + // Return
  251 + return;
  252 +}
  253 +
  254 +
  255 +/***********************************************************************//**
  256 + * @brief Copy class members
  257 + *
  258 + * @param[in] hub VO hub.
  259 + ***************************************************************************/
  260 +void GVOHub::copy_members(const GVOHub& hub)
  261 +{
  262 + // Copy members
  263 + m_secret = hub.m_secret;
  264 + m_hub_url = hub.m_hub_url;
  265 + m_hub_host = hub.m_hub_host;
  266 + m_hub_port = hub.m_hub_port;
  267 + m_hub_path = hub.m_hub_path;
  268 + m_version = hub.m_version;
  269 + m_hub_id = hub.m_hub_id;
  270 + m_socket = hub.m_socket;
  271 + m_shutdown = hub.m_shutdown;
  272 + m_clients = hub.m_clients;
  273 +
  274 + // Return
  275 + return;
  276 +}
  277 +
  278 +
  279 +/***********************************************************************//**
  280 + * @brief Delete class members
  281 + ***************************************************************************/
  282 +void GVOHub::free_members(void)
  283 +{
  284 + // Close sockets
  285 + if (m_socket != -1) {
  286 + close(m_socket);
  287 + m_socket = -1;
  288 + }
  289 +
  290 + // Remove lockfile
  291 + std::string lockurl = get_hub_lockfile();
  292 + std::remove(lockurl.c_str());
  293 +
  294 + // Return
  295 + return;
  296 +}
  297 +
  298 +
  299 +/***********************************************************************//**
  300 + * @brief Starts the SAMP hub socket and listens on it
  301 + *
  302 + * @exception GException::runtime_error
  303 + * Problem with creating of or listening on socket
  304 + *
  305 + * This is the main Hub event loop.
  306 + ***************************************************************************/
  307 +void GVOHub::start_hub(void)
  308 +{
  309 + // Prepare TCP/IP structure
  310 + struct sockaddr_in serv_addr;
  311 + std::memset(&serv_addr, 0, sizeof(serv_addr));
  312 + serv_addr.sin_family = AF_INET;
  313 + serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str());
  314 + serv_addr.sin_port = htons(gammalib::toint(m_hub_port));
  315 +
  316 + // Create Hub socket
  317 + m_socket = socket(AF_INET, SOCK_STREAM, 0);
  318 +
  319 + // Creation of hub main socket
  320 + if (m_socket < 0) {
  321 + std::string msg = "Unable to create Hub socket. Errno="+
  322 + gammalib::str(errno);
  323 + throw GException::runtime_error(G_START_HUB, msg);
  324 + }
  325 +
  326 + // Set hub main socket to allow multiple connections
  327 + int opt = 1;
  328 + if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
  329 + std::string msg = "Unable to set Hub socket to multiple connections."
  330 + " Errno="+gammalib::str(errno);
  331 + throw GException::runtime_error(G_START_HUB, msg);
  332 + }
  333 + #ifdef SO_REUSEPORT
  334 + if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) {
  335 + std::string msg = "Unable to set Hub socket to multiple connections."
  336 + " Errno="+gammalib::str(errno);
  337 + throw GException::runtime_error(G_START_HUB, msg);
  338 + }
  339 + #endif
  340 +
  341 + // Server socket is opened. Now, bind it to the port, with family etc.
  342 + if (bind(m_socket, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
  343 + std::string msg = "Unable to bind Hub socket to server socket. Errno="+
  344 + gammalib::str(errno);
  345 + throw GException::runtime_error(G_START_HUB, msg);
  346 + }
  347 +
  348 + // Now start listening for the clients: 5 requests simultaneously pending
  349 + // at maximum
  350 + if (listen(m_socket, 5) < 0) {
  351 + std::string msg = "Unable to start listening on Hub socket. Errno="+
  352 + gammalib::str(errno);
  353 + throw GException::runtime_error(G_START_HUB, msg);
  354 + }
  355 +
  356 + // ...
  357 + struct sockaddr_in cli_addr;
  358 + socklen_t clilen = sizeof(cli_addr);
  359 +
  360 + // Main event handling loop
  361 + while (1) {
  362 +
  363 + // Accept connection from the client
  364 + socklen_t socket = accept(m_socket, (struct sockaddr *)&cli_addr, &clilen);
  365 + if (socket < 0) {
  366 + std::string msg = "Client connection to socket not accepted.";
  367 + throw GException::runtime_error(G_START_HUB, msg);
  368 + }
  369 +
  370 + // Handle request
  371 + handle_request(socket);
  372 +
  373 + // Close socket
  374 + close(socket);
  375 +
  376 + // If we have received a shutdown request then exit the event
  377 + // loop
  378 + if (m_shutdown) {
  379 + break;
  380 + }
  381 +
  382 + } // endwhile: main event loop
  383 +
  384 + // Close socket
  385 + close(m_socket);
  386 + m_socket = -1;
  387 +
  388 + // Return
  389 + return;
  390 +}
  391 +
  392 +
  393 +/***********************************************************************//**
  394 + * @brief Reads the client message and runs appropriate function
  395 + *
  396 + * @param[in] sock Socket to client.
  397 + ***************************************************************************/
  398 +void GVOHub::handle_request(const socklen_t& sock)
  399 +{
  400 + // Header
  401 + #if defined(G_CONSOLE_DUMP)
  402 + std::cout << "GVOHub::handle_request" << std::endl;
  403 + #endif
  404 +
  405 + // Initialize buffer
  406 + char buffer[1001];
  407 +
  408 + // Initialise message
  409 + std::string message = "";
  410 +
  411 + // Read from socket until nothing is received anymore.
  412 + int timeout = 2000; // Initial timeout is 2 sec
  413 + int n = 0;
  414 + do {
  415 + n = gammalib::recv(sock, buffer, 1000, 0, timeout);
  416 + if (n > 0) {
  417 + buffer[n] = '\0';
  418 + message.append(std::string(buffer));
  419 + }
  420 + timeout = 10; // The timeout now is 0.01 sec
  421 + } while (n > 0);
  422 +
  423 + // Dump the buffer
  424 + #if defined(G_SHOW_MESSAGE)
  425 + std::cout << std::endl;
  426 + std::cout << "GVOHub has received the following message:" << std::endl;
  427 + std::cout << "==========================================" << std::endl;
  428 + std::cout << message << std::endl;
  429 + #endif
  430 +
  431 + // Extract response into an XML object
  432 + GXml xml;
  433 + size_t start = message.find("<?xml");
  434 + if (start != std::string::npos) {
  435 + xml = GXml(message.substr(start, std::string::npos));
  436 + }
  437 +
  438 + // Get methodName value
  439 + std::string method_called;
  440 + const GXmlNode* node = xml.element("methodCall > methodName");
  441 + if (node != NULL) {
  442 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  443 + if (text != NULL) {
  444 + method_called = text->text();
  445 + }
  446 + }
  447 +
  448 + // Dump the buffer
  449 + #if defined(G_CONSOLE_DUMP)
  450 + std::cout << "Method called: " << method_called << std::endl;
  451 + #endif
  452 +
  453 + // Dispatch according to method
  454 + if (method_called.compare("samp.hub.ping") == 0) {
  455 + request_ping(sock);
  456 + }
  457 + else if (method_called.compare("samp.hub.register") == 0) {
  458 + request_register(xml, sock);
  459 + }
  460 + else if (method_called.compare("samp.hub.unregister") == 0) {
  461 + request_unregister(xml, sock);
  462 + }
  463 + else if (method_called.compare("samp.hub.declareMetadata") == 0) {
  464 + request_declare_metadata(xml, sock);
  465 + }
  466 + else if (method_called.compare("samp.hub.declareSubscriptions") == 0) {
  467 + request_declare_subscriptions(xml, sock);
  468 + }
  469 + else if (method_called.compare("samp.hub.setXmlrpcCallback") == 0) {
  470 + request_set_xml_rpc_callback(xml, sock);
  471 + }
  472 + else if (method_called.compare("samp.hub.getSubscriptions") == 0) {
  473 + request_get_subscriptions(xml, sock);
  474 + }
  475 + else if (method_called.compare("samp.hub.getRegisteredClients") == 0) {
  476 + request_get_registered_clients(xml, sock);
  477 + }
  478 + else if (method_called.compare("samp.hub.getSubscribedClients") == 0) {
  479 + request_get_subscribed_clients(xml, sock);
  480 + }
  481 + else if (method_called.compare("samp.hub.getMetadata") == 0) {
  482 + request_get_metadata(xml, sock);
  483 + }
  484 + else if (method_called.compare("samp.hub.notify") == 0) {
  485 + request_ping(sock);
  486 + }
  487 + else if (method_called.compare("samp.hub.notifyAll") == 0) {
  488 + request_ping(sock);
  489 + }
  490 + else if (method_called.compare("samp.hub.call") == 0) {
  491 + request_call(xml,sock);
  492 + }
  493 + else if (method_called.compare("samp.hub.callAll") == 0) {
  494 + request_ping(sock);
  495 + }
  496 + else if (method_called.compare("samp.hub.callAndWait") == 0) {
  497 + request_ping(sock);
  498 + }
  499 + else if (method_called.compare("samp.hub.reply") == 0) {
  500 + request_ping(sock);
  501 + }
  502 + else if (method_called.compare("samp.hub.shutdown") == 0) {
  503 + request_shutdown(sock);
  504 + }
  505 +
  506 + // Return
  507 + return;
  508 +}
  509 +
  510 +
  511 +/***********************************************************************//**
  512 + * @brief Handles ping requests
  513 + *
  514 + * @param[in] sock Socket.
  515 + *
  516 + * Handles all incoming ping requests.
  517 + ***************************************************************************/
  518 +void GVOHub::request_ping(const socklen_t& sock)
  519 +{
  520 + // Header
  521 + #if defined(G_CONSOLE_DUMP)
  522 + std::cout << "GVOHub::request_ping" << std::endl;
  523 + #endif
  524 +
  525 + // Post void message
  526 + post_samp_void(sock);
  527 +
  528 + // Return
  529 + return;
  530 +}
  531 +
  532 +
  533 +/***********************************************************************//**
  534 + * @brief Handles registration requests
  535 + *
  536 + * @param[in] xml XML message sent by client.
  537 + * @param[in] sock Socket.
  538 + *
  539 + * Handles all incoming registration requests.
  540 + ***************************************************************************/
  541 +void GVOHub::request_register(const GXml& xml, const socklen_t& sock)
  542 +{
  543 + // Header
  544 + #if defined(G_CONSOLE_DUMP)
  545 + std::cout << "GVOHub::request_register" << std::endl;
  546 + #endif
  547 +
  548 + // Set client reference
  549 + int counter = 0;
  550 + std::string reference;
  551 + do {
  552 + reference = "c"+gammalib::str(counter);
  553 + int i = 0;
  554 + for (; i < m_clients.size(); ++i) {
  555 + if (m_clients[i].reference == reference) {
  556 + counter++;
  557 + break;
  558 + }
  559 + }
  560 + if (i >= m_clients.size()) {
  561 + break;
  562 + }
  563 + } while (true);
  564 +
  565 + // Create a new client
  566 + struct client voclient;
  567 + voclient.reference = reference;
  568 + voclient.private_key = random_string(15);
  569 +
  570 + // Attached client
  571 + m_clients.push_back(voclient);
  572 +
  573 + // Declare response
  574 + std::string response = "";
  575 +
  576 + // Set response
  577 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  578 + response.append("<methodResponse>\n");
  579 + response.append("<params>\n");
  580 + response.append(" <param><value><struct>\n");
  581 + response.append(" <member>\n");
  582 + response.append(" <name>samp.private-key</name>\n");
  583 + response.append(" <value>"+voclient.private_key+"</value>\n");
  584 + response.append(" </member>\n");
  585 + response.append(" <member>\n");
  586 + response.append(" <name>samp.hub-id</name>\n");
  587 + response.append(" <value>"+m_hub_id+"</value>\n");
  588 + response.append(" </member>\n");
  589 + response.append(" <member>\n");
  590 + response.append(" <name>samp.self-id</name>\n");
  591 + response.append(" <value>"+voclient.reference+"</value>\n");
  592 + response.append(" </member>\n");
  593 + response.append(" <member>\n");
  594 + response.append(" <name>samp.status</name>\n");
  595 + response.append(" <value>samp.ok</value>\n");
  596 + response.append(" </member>\n");
  597 + response.append(" <member>\n");
  598 + response.append(" <name>samp.url-translator</name>\n");
  599 + response.append(" <value>"+m_hub_url+"</value>\n");
  600 + response.append(" </member>\n");
  601 + response.append(" </struct></value></param>\n");
  602 + response.append("</params>\n");
  603 + response.append("</methodResponse>\n");
  604 +
  605 + // Post response
  606 + post_string(response, sock);
  607 +
  608 + // Send notifications
  609 + send_notifications("samp.hub.event.register", voclient.reference);
  610 +
  611 + //Return
  612 + return;
  613 +}
  614 +
  615 +
  616 +/***********************************************************************//**
  617 + * @brief Handles unregistration requests
  618 + *
  619 + * @param[in] xml XML message sent by client.
  620 + * @param[in] sock Socket.
  621 + *
  622 + * Handles all incoming unregistration requests.
  623 + ***************************************************************************/
  624 +void GVOHub::request_unregister(const GXml& xml, const socklen_t& sock)
  625 +{
  626 + // Optionally dump header
  627 + #if defined(G_CONSOLE_DUMP)
  628 + std::cout << "GVOHub::request_unregister" << std::endl;
  629 + #endif
  630 +
  631 + // Get client index
  632 + int i = get_client_index(xml);
  633 +
  634 + // Continue only if index is valid
  635 + if (i != -1) {
  636 +
  637 + // Post void message
  638 + post_samp_void(sock);
  639 +
  640 + // Send notifications
  641 + send_notifications("samp.hub.event.unregister",
  642 + m_clients[i].reference);
  643 +
  644 + // Remove client
  645 + m_clients.erase(m_clients.begin()+i);
  646 +
  647 + } // endif: valid client found
  648 +
  649 + // Signal if the client was unknown
  650 + #if defined(G_CONSOLE_DUMP)
  651 + else {
  652 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  653 + }
  654 + #endif
  655 +
  656 + // Return
  657 + return;
  658 +}
  659 +
  660 +
  661 +/***********************************************************************//**
  662 + * @brief Handles metadata declaration requests
  663 + *
  664 + * @param[in] xml XML message sent by client.
  665 + * @param[in] sock Socket.
  666 + *
  667 + * Handles all incoming metadata declaration requests.
  668 + ***************************************************************************/
  669 +void GVOHub::request_declare_metadata(const GXml& xml, const socklen_t& sock)
  670 +{
  671 + // Header
  672 + #if defined(G_CONSOLE_DUMP)
  673 + std::cout << "GVOHub::request_declare_metadata" << std::endl;
  674 + #endif
  675 +
  676 + // Get client index
  677 + int i = get_client_index(xml);
  678 +
  679 + // Continue only if index is valid
  680 + if (i != -1) {
  681 +
  682 + // Store metadata
  683 + m_clients[i].name = get_response_value(xml, "samp.name");;
  684 + m_clients[i].description = get_response_value(xml, "samp.description.text");
  685 + m_clients[i].icon = get_response_value(xml, "samp.icon.url");
  686 + m_clients[i].documentation = get_response_value(xml, "samp.documentation.url");
  687 + m_clients[i].affiliation = get_response_value(xml, "author.affiliation");
  688 + m_clients[i].email = get_response_value(xml, "author.email");
  689 + m_clients[i].author_name = get_response_value(xml, "author.name");
  690 + m_clients[i].homepage = get_response_value(xml, "home.page");
  691 +
  692 + // Post void message
  693 + post_samp_void(sock);
  694 +
  695 + // Send notifications
  696 + send_notifications("samp.hub.event.metadata", m_clients[i].reference);
  697 +
  698 + } // endif: client found
  699 +
  700 + // Signal if the client was unknown
  701 + #if defined(G_CONSOLE_DUMP)
  702 + else {
  703 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  704 + }
  705 + #endif
  706 +
  707 + // Return
  708 + return;
  709 +}
  710 +
  711 +
  712 +/***********************************************************************//**
  713 + * @brief Handles subscriptions declaration requests
  714 + *
  715 + * @param[in] xml XML message sent by client.
  716 + * @param[in] sock Socket.
  717 + *
  718 + * Handles all incoming subscription declaration requests.
  719 + ***************************************************************************/
  720 +void GVOHub::request_declare_subscriptions(const GXml& xml,const socklen_t& sock)
  721 +{
  722 + // Header
  723 + #if defined(G_CONSOLE_DUMP)
  724 + std::cout << "GVOHub::request_declare_subscriptions" << std::endl;
  725 + #endif
  726 +
  727 + // Get client index
  728 + int i = get_client_index(xml);
  729 +
  730 + // Continue only if index is valid
  731 + if (i != -1) {
  732 +
  733 + // Get subscriptions
  734 + std::vector<std::string> subscriptions = get_subscriptions(xml);
  735 +
  736 + // Store subscriptions
  737 + for (int k = 0; k < subscriptions.size(); ++k) {
  738 + m_clients[i].subscriptions.push_back(subscriptions[k]);
  739 + }
  740 +
  741 + // Post SAMP ok
  742 + post_samp_ok(sock);
  743 +
  744 + } // endif: valid client found
  745 +
  746 + // Signal if the client was unknown
  747 + #if defined(G_CONSOLE_DUMP)
  748 + else {
  749 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  750 + }
  751 + #endif
  752 +
  753 + //Return
  754 + return;
  755 +}
  756 +
  757 +
  758 +/***********************************************************************//**
  759 + * @brief Handles XML-RPC callback setting requests
  760 + *
  761 + * @param[in] xml XML message sent by client.
  762 + * @param[in] sock Socket.
  763 + *
  764 + * Handles all incoming XML-RPC callback setting requests.
  765 + ***************************************************************************/
  766 +void GVOHub::request_set_xml_rpc_callback(const GXml& xml,
  767 + const socklen_t& sock)
  768 +{
  769 + // Header
  770 + #if defined(G_CONSOLE_DUMP)
  771 + std::cout << "GVOHub::request_set_xml_rpc_callback" << std::endl;
  772 + #endif
  773 +
  774 + // Get client index
  775 + int i = get_client_index(xml);
  776 +
  777 + // Continue only if index is valid
  778 + if (i != -1) {
  779 +
  780 + // Get callback URL
  781 + std::string client_url = get_callback_url(xml);
  782 +
  783 + // Set callback URL
  784 + m_clients[i].url = get_callback_url(xml);
  785 +
  786 + // Post SAMP ok
  787 + post_samp_ok(sock);
  788 +
  789 + } // endif: client found
  790 +
  791 + // Signal if the client was unknown
  792 + #if defined(G_CONSOLE_DUMP)
  793 + else {
  794 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  795 + }
  796 + #endif
  797 +
  798 + // Return
  799 + return;
  800 +}
  801 +
  802 +
  803 +/***********************************************************************//**
  804 + * @brief Handles subscriptions getting requests
  805 + *
  806 + * @param[in] xml XML message sent by client.
  807 + * @param[in] sock Socket.
  808 + *
  809 + * Handles all incoming subscriptions getting requests.
  810 + ***************************************************************************/
  811 +void GVOHub::request_get_subscriptions(const GXml& xml, const socklen_t& sock)
  812 +{
  813 + // Header
  814 + #if defined(G_CONSOLE_DUMP)
  815 + std::cout << "GVOHub::request_get_subscriptions" << std::endl;
  816 + #endif
  817 +
  818 + // Initialise client name
  819 + std::string client_name = "";
  820 +
  821 + // Get the client name
  822 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value");
  823 + if (node != NULL) {
  824 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  825 + if (text != NULL) {
  826 + client_name = text->text();
  827 + }
  828 + }
  829 +
  830 + // Declare response
  831 + std::string response = "";
  832 +
  833 + // Set response
  834 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  835 + response.append("<methodResponse>\n");
  836 + response.append("<params>\n");
  837 + response.append(" <param><value><struct>\n");
  838 +
  839 + // If key is "gammalib_hub" then return some special information
  840 + if (client_name == "gammalib_hub") {
  841 + // Do nothing
  842 + }
  843 +
  844 + // ... handle all other clients
  845 + else {
  846 +
  847 + // Get client index
  848 + int i = get_client_index(client_name);
  849 +
  850 + // Continue only if index is valid
  851 + if (i != -1) {
  852 +
  853 + // Append all subscriptions
  854 + for (int k = 0; k < m_clients[i].subscriptions.size(); ++k) {
  855 + response.append(" <member>\n");
  856 + response.append(" <name>");
  857 + response.append(m_clients[i].subscriptions[k]);
  858 + response.append("</name>\n");
  859 + response.append(" <value></value>\n");
  860 + response.append(" </member>\n");
  861 + }
  862 +
  863 + }
  864 +
  865 + // Signal if the client was unknown
  866 + #if defined(G_CONSOLE_DUMP)
  867 + else {
  868 + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl;
  869 + }
  870 + #endif
  871 +
  872 + }
  873 +
  874 + // Finish response
  875 + response.append(" </struct></value></param>\n");
  876 + response.append("</params>\n");
  877 + response.append("</methodResponse>\n");
  878 +
  879 + // Post response
  880 + post_string(response, sock);
  881 +
  882 + // Return
  883 + return;
  884 +}
  885 +
  886 +
  887 +/***********************************************************************//**
  888 + * @brief Handles registered client information requests
  889 + *
  890 + * @param[in] xml XML message sent by client.
  891 + * @param[in] sock Socket.
  892 + *
  893 + * Handles all incoming registered client information requests.
  894 + ***************************************************************************/
  895 +void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& sock)
  896 +{
  897 + // Header
  898 + #if defined(G_CONSOLE_DUMP)
  899 + std::cout << "GVOHub::request_get_registered_clients" << std::endl;
  900 + #endif
  901 +
  902 + // Get client key
  903 + std::string key = get_client_key(xml);
  904 +
  905 + // Declare message
  906 + std::string msg = "";
  907 + // Set response
  908 + msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
  909 + msg.append("<methodResponse>\n");
  910 + msg.append("<params>\n");
  911 + msg.append(" <param><value><array><data>\n");
  912 + msg.append(" <value>gammalib_hub</value>\n");
  913 +
  914 + // Loop over all clients. Do not send back current client's registration
  915 + for (int i = 0; i < m_clients.size(); ++i) {
  916 + if (m_clients[i].private_key != key) {
  917 + msg.append(" <value>");
  918 + msg.append(m_clients[i].reference);
  919 + msg.append("</value>\n");
  920 + }
  921 + }
  922 +
  923 + // Finish response
  924 + msg.append(" </data></array></value></param>\n");
  925 + msg.append("</params>\n");
  926 + msg.append("</methodResponse>\n");
  927 + // Post response
  928 + post_string(msg, sock);
  929 +
  930 + // Return
  931 + return;
  932 +
  933 +}
  934 +
  935 +
  936 +/***********************************************************************//**
  937 + * @brief Handles subscribed client information requests
  938 + *
  939 + * @param[in] xml XML message sent by client.
  940 + * @param[in] sock Socket.
  941 + *
  942 + * Handles all incoming subscribed client information requests.
  943 + ***************************************************************************/
  944 +void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& sock)
  945 +{
  946 + // Header
  947 + #if defined(G_CONSOLE_DUMP)
  948 + std::cout << "GVOHub::request_get_subscribed_clients" << std::endl;
  949 + #endif
  950 +
  951 + // Declare message
  952 + std::string msg = "";
  953 +
  954 + msg.append("<?xml version=\'1.0\' encoding=\"UTF-8\"?>\n");
  955 + msg.append("<methodResponse>\n");
  956 + msg.append("<params>\n");
  957 + msg.append(" <param><value><struct><member><name>c0</name><value><struct></struct></value></member><member><name>gammalib_hub</name><value><struct></struct></value></member></struct></value></param></params></methodResponse>");
  958 +
  959 +/*
  960 + std::string buffer;
  961 + const int n = 1000;
  962 + char line[n];
  963 + FILE* fptr = fopen("SAMP-registered.txt", "r");
  964 + if (fptr != NULL) {
  965 + while (fgets(line, n, fptr) != NULL) {
  966 +
  967 + // Convert line to C++ string
  968 + std::string cline = std::string(line);
  969 +
  970 + // Check for secret key
  971 + if (cline.compare(0, 10, "Registered") == 0) {
  972 + buffer = gammalib::strip_chars(cline.substr(10, std::string::npos), "\r\n");
  973 + }
  974 + }
  975 +
  976 + // Closes file
  977 + fclose(fptr);
  978 +*/
  979 +
  980 + // Post response
  981 + post_string(msg, sock);
  982 + // Post void message
  983 + //post_samp_void(sock);
  984 +
  985 + // Return
  986 + return;
  987 +}
  988 +
  989 +
  990 +/***********************************************************************//**
  991 + * @brief Handles a metadata requests
  992 + *
  993 + * @param[in] xml XML message sent by client.
  994 + * @param[in] sock Socket.
  995 + *
  996 + * Handles all metadata requests.
  997 + ***************************************************************************/
  998 +void GVOHub::request_get_metadata(const GXml& xml, const socklen_t& sock)
  999 +{
  1000 + // Header
  1001 + #if defined(G_CONSOLE_DUMP)
  1002 + std::cout << "GVOHub::request_get_metadata" << std::endl;
  1003 + #endif
  1004 +
  1005 + // Initialise client name
  1006 + std::string client_name = "";
  1007 +
  1008 + // Get the client name
  1009 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value");
  1010 + if (node != NULL) {
  1011 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  1012 + if (text != NULL) {
  1013 + client_name = text->text();
  1014 + }
  1015 + }
  1016 +
  1017 + // Declare response
  1018 + std::string response = "";
  1019 +
  1020 + // Set response
  1021 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  1022 + response.append("<methodResponse>\n");
  1023 + response.append("<params>\n");
  1024 + response.append(" <param><value><struct>\n");
  1025 + response.append(" <member>\n");
  1026 + response.append(" <name>samp.status</name>\n");
  1027 + response.append(" <value>samp.ok</value>\n");
  1028 + response.append(" </member>\n");
  1029 +
  1030 + // If key is "gammalib_hub" then return some special information
  1031 + if (client_name == "gammalib_hub") {
  1032 + response.append(" <member>\n");
  1033 + response.append(" <name>samp.name</name>\n");
  1034 + response.append(" <value>gammalib_hub</value>\n");
  1035 + response.append(" </member>\n");
  1036 + response.append(" <member>\n");
  1037 + response.append(" <name>samp.description.text</name>\n");
  1038 + response.append(" <value>GammaLib VO Hub</value>\n");
  1039 + response.append(" </member>\n");
  1040 + response.append(" <member>\n");
  1041 + response.append(" <name>samp.icon.url</name>\n");
  1042 + response.append(" <value>http://a.fsdn.com/allura/p/gammalib/icon</value>\n");
  1043 + response.append(" </member>\n");
  1044 + response.append(" <member>\n");
  1045 + response.append(" <name>samp.documentation.url</name>\n");
  1046 + response.append(" <value>http://cta.irap.omp.eu/gammalib/user_manual/modules/vo.html</value>\n");
  1047 + response.append(" </member>\n");
  1048 + response.append(" <member>\n");
  1049 + response.append(" <name>author.affiliation</name>\n");
  1050 + response.append(" <value>IRAP, Toulouse, France</value>\n");
  1051 + response.append(" </member>\n");
  1052 + response.append(" <member>\n");
  1053 + response.append(" <name>author.email</name>\n");
  1054 + response.append(" <value>jurgen.knodlseder@irap.omp.eu</value>\n");
  1055 + response.append(" </member>\n");
  1056 + response.append(" <member>\n");
  1057 + response.append(" <name>author.name</name>\n");
  1058 + response.append(" <value>J. Knoedlseder, T. Louge</value>\n");
  1059 + response.append(" </member>\n");
  1060 + response.append(" <member>\n");
  1061 + response.append(" <name>home.page</name>\n");
  1062 + response.append(" <value>http://cta.irap.omp.eu/gammalib/</value>\n");
  1063 + response.append(" </member>\n");
  1064 + }
  1065 +
  1066 + // ... otherwise get the index
  1067 + else {
  1068 +
  1069 + // Get client index
  1070 + int i = get_client_index(client_name);
  1071 +
  1072 + // Continue only if index is valid
  1073 + if (i != -1) {
  1074 +
  1075 + // Append response
  1076 + response.append(" <member>\n");
  1077 + response.append(" <name>samp.name</name>\n");
  1078 + response.append(" <value>"+m_clients[i].name+"</value>\n");
  1079 + response.append(" </member>\n");
  1080 + response.append(" <member>\n");
  1081 + response.append(" <name>samp.description.text</name>\n");
  1082 + response.append(" <value>"+m_clients[i].description+"</value>\n");
  1083 + response.append(" </member>\n");
  1084 + response.append(" <member>\n");
  1085 + response.append(" <name>samp.icon.url</name>\n");
  1086 + response.append(" <value>"+m_clients[i].icon+"</value>\n");
  1087 + response.append(" </member>\n");
  1088 + response.append(" <member>\n");
  1089 + response.append(" <name>samp.documentation.url</name>\n");
  1090 + response.append(" <value>"+m_clients[i].documentation+"</value>\n");
  1091 + response.append(" </member>\n");
  1092 + response.append(" <member>\n");
  1093 + response.append(" <name>author.affiliation</name>\n");
  1094 + response.append(" <value>"+m_clients[i].affiliation+"</value>\n");
  1095 + response.append(" </member>\n");
  1096 + response.append(" <member>\n");
  1097 + response.append(" <name>author.email</name>\n");
  1098 + response.append(" <value>"+m_clients[i].email+"</value>\n");
  1099 + response.append(" </member>\n");
  1100 + response.append(" <member>\n");
  1101 + response.append(" <name>author.name</name>\n");
  1102 + response.append(" <value>"+m_clients[i].author_name+"</value>\n");
  1103 + response.append(" </member>\n");
  1104 + response.append(" <member>\n");
  1105 + response.append(" <name>home.page</name>\n");
  1106 + response.append(" <value>"+m_clients[i].homepage+"</value>\n");
  1107 + response.append(" </member>\n");
  1108 +
  1109 + } // endif: index was valid
  1110 +
  1111 + } // endelse: client was not the hub
  1112 +
  1113 + // Finish response
  1114 + response.append(" </struct></value></param>\n");
  1115 + response.append("</params>\n");
  1116 + response.append("</methodResponse>\n");
  1117 +
  1118 + // Post response
  1119 + post_string(response, sock);
  1120 +
  1121 + // Return
  1122 + return;
  1123 +}
  1124 +
  1125 +/***********************************************************************//**
  1126 + * @brief Handles calls to specific client
  1127 + *
  1128 + * @param[in] xml XML message sent by client.
  1129 + * @param[in] sock Socket.
  1130 + *
  1131 + * Handles all incoming cals for a specific client
  1132 + ***************************************************************************/
  1133 +void GVOHub::request_call(const GXml& xml, const socklen_t& sock)
  1134 +{
  1135 + // Header
  1136 + #if defined(G_CONSOLE_DUMP)
  1137 + std::cout << "GVOHub::request_get_registered_clients" << std::endl;
  1138 + #endif
  1139 +
  1140 + // Get client key
  1141 + std::string key = get_client_key(xml);
  1142 + // Get message mtype
  1143 + std::string mtype = get_mtype(xml);
  1144 + // Get the key of client who is to be contacted with the message
  1145 + // Declare message
  1146 + std::string msg = "";
  1147 + // Determine which call has been invoqued
  1148 + // Loop over all clients and send notification
  1149 + for (int i = 0; i < m_clients.size(); ++i) {
  1150 + msg = "";
  1151 +
  1152 + // Set response for table.load.votable
  1153 + msg.append("<?xml version=\"1.0\"?>\n");
  1154 + msg.append("<methodCall><methodName>samp.client.receiveCall</methodName>\n");
  1155 + msg.append("<params>\n");
  1156 + msg.append(" <param><value>");
  1157 + msg.append(m_clients[i].private_key);
  1158 + msg.append("</value></param>\n");
  1159 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1160 + msg.append(" <param><value><struct>\n");
  1161 + msg.append(" <member>\n");
  1162 + msg.append(" <name>samp.mtype</name>\n");
  1163 + msg.append(" <value>table.load.votable</value>\n");
  1164 + msg.append(" </member>\n");
  1165 + msg.append(" <member>\n");
  1166 + msg.append(" <name>samp.params</name>\n");
  1167 + msg.append(" <value><struct>\n");
  1168 + msg.append(" <member>\n");
  1169 + msg.append(" <name>name</name>\n");
  1170 + msg.append(" <value>imagename</value>\n");
  1171 + msg.append(" </member>\n");
  1172 + msg.append(" <member>\n");
  1173 + msg.append(" <name>table-id</name>\n");
  1174 + msg.append(" <value>id of table</value>\n");
  1175 + msg.append(" </member>\n");
  1176 + msg.append(" <member>\n");
  1177 + msg.append(" <name>url</name>\n");
  1178 + msg.append(" <value>url to the table</value>\n");
  1179 + msg.append(" </member>\n");
  1180 + msg.append(" </struct></value>\n");
  1181 + msg.append(" </member>\n");
  1182 + msg.append(" </struct></value>\n");
  1183 + msg.append(" </param>\n");
  1184 + msg.append("</params>\n");
  1185 + msg.append("</methodCall>\n");
  1186 +
  1187 +
  1188 + // Post notification
  1189 + notify(m_clients[i].url, msg);
  1190 + }
  1191 +
  1192 + // Return
  1193 + return;
  1194 +
  1195 +}
  1196 +
  1197 +/***********************************************************************//**
  1198 + * @brief Handles Hub shutdown requests
  1199 + *
  1200 + * @param[in] sock Socket.
  1201 + *
  1202 + * Handles all incoming Hub shutdown requests.
  1203 + ***************************************************************************/
  1204 +void GVOHub::request_shutdown(const socklen_t& sock)
  1205 +{
  1206 + // Header
  1207 + #if defined(G_CONSOLE_DUMP)
  1208 + std::cout << "GVOHub::request_shutdown" << std::endl;
  1209 + #endif
  1210 +
  1211 + // Set shutdown flag
  1212 + m_shutdown = true;
  1213 +
  1214 + // Post SAMP ok
  1215 + post_samp_ok(sock);
  1216 +
  1217 + // Return
  1218 + return;
  1219 +}
  1220 +
  1221 +
  1222 +/***********************************************************************//**
  1223 + * @brief Extract client key from XML request
  1224 + *
  1225 + * @param[in] xml XML message sent by client.
  1226 + *
  1227 + * Extracts the clients key from the XML request.
  1228 + ***************************************************************************/
  1229 +std::string GVOHub::get_client_key(const GXml& xml) const
  1230 +{
  1231 + // Header
  1232 + #if defined(G_CONSOLE_DUMP)
  1233 + std::cout << "GVOHub::get_client_key" << std::endl;
  1234 + #endif
  1235 +
  1236 + // Initialise response
  1237 + std::string client_key = "";
  1238 +
  1239 + // Get the client's private key
  1240 + const GXmlNode* node = xml.element("methodCall > params > param > value");
  1241 + if (node != NULL) {
  1242 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  1243 + if (text != NULL) {
  1244 + client_key = text->text();
  1245 + }
  1246 + }
  1247 +
  1248 + // Return key
  1249 + return client_key;
  1250 +}
  1251 +
  1252 +
  1253 +/***********************************************************************//**
  1254 + * @brief Extract client index in shared memory from XML request
  1255 + *
  1256 + * @param[in] xml XML message sent by client.
  1257 + * @return Client index (-1 if not found).
  1258 + *
  1259 + * Extracts the client index from the XML request. The method returns -1 if
  1260 + * no client was found.
  1261 + ***************************************************************************/
  1262 +int GVOHub::get_client_index(const GXml& xml) const
  1263 +{
  1264 + // Header
  1265 + #if defined(G_CONSOLE_DUMP)
  1266 + std::cout << "GVOHub::get_client_index" << std::endl;
  1267 + #endif
  1268 +
  1269 + // Initialise index
  1270 + int index = -1;
  1271 +
  1272 + // Get the client's private key
  1273 + std::string key = get_client_key(xml);
  1274 +
  1275 + // Continue only if string is not empty
  1276 + if (!key.empty()) {
  1277 +
  1278 + // Searches for key in clients
  1279 + for (int i = 0; i < m_clients.size(); ++i) {
  1280 + if (m_clients[i].private_key == key) {
  1281 + index = i;
  1282 + break;
  1283 + }
  1284 + }
  1285 +
  1286 + } // endif: key was not empty
  1287 +
  1288 + // Return index
  1289 + return index;
  1290 +}
  1291 +
  1292 +
  1293 +/***********************************************************************//**
  1294 + * @brief Extract client index in shared memory from XML request
  1295 + *
  1296 + * @param[in] reference Client reference.
  1297 + * @return Client index (-1 if not found).
  1298 + *
  1299 + * Extracts the client index from the client reference. The method returns -1
  1300 + * if no client was found.
  1301 + ***************************************************************************/
  1302 +int GVOHub::get_client_index(const std::string& reference) const
  1303 +{
  1304 + // Header
  1305 + #if defined(G_CONSOLE_DUMP)
  1306 + std::cout << "GVOHub::get_client_index" << std::endl;
  1307 + #endif
  1308 +
  1309 + // Initialise index
  1310 + int index = -1;
  1311 +
  1312 + // Search for index
  1313 + for (int i = 0; i < m_clients.size(); ++i) {
  1314 + if (m_clients[i].reference == reference) {
  1315 + index = i;
  1316 + break;
  1317 + }
  1318 + }
  1319 +
  1320 + // Return index
  1321 + return index;
  1322 +}
  1323 +
  1324 +
  1325 +/***********************************************************************//**
  1326 + * @brief Returns value for a SAMP client query parameter
  1327 + *
  1328 + * @param[in] xml client query XML document.
  1329 + * @param[in] name Parameter name.
  1330 + * @return Parameter value.
  1331 + *
  1332 + * Returns value for a SAMP client query parameter. If the specified
  1333 + * parameter was not found or if the response structure is not compliant,
  1334 + * an empty string is returned.
  1335 + ***************************************************************************/
  1336 +std::string GVOHub::get_response_value(const GXml& xml,
  1337 + const std::string& name) const
  1338 +{
  1339 + // Declare value
  1340 + std::string value = "";
  1341 +
  1342 + // Get the client's private key
  1343 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct");
  1344 + if (node != NULL) {
  1345 + int num = node->elements("member");
  1346 + for (int i = 0; i < num; ++i) {
  1347 + const GXmlNode* member = node->element("member", i);
  1348 + std::string one_name;
  1349 + std::string one_value;
  1350 + get_name_value_pair(member, one_name, one_value);
  1351 + if (one_name == name) {
  1352 + value = one_value;
  1353 + break;
  1354 + }
  1355 + }
  1356 +
  1357 + }
  1358 +
  1359 + // Return value
  1360 + return value;
  1361 +}
  1362 +
  1363 +
  1364 +/***********************************************************************//**
  1365 + * @brief Extract name / value pair from XML node
  1366 + *
  1367 + * @param[in] node Pointer to XML node.
  1368 + * @param[out] name Name string.
  1369 + * @param[out] value Value string.
  1370 + *
  1371 + * Extracts a name / value pair from a XML node. If the XML node pointer is
  1372 + * NULL, the name and value strings will be empty.
  1373 + ***************************************************************************/
  1374 +void GVOHub::get_name_value_pair(const GXmlNode* node,
  1375 + std::string& name,
  1376 + std::string& value) const
  1377 +{
  1378 + // Clear name and value strings
  1379 + name.clear();
  1380 + value.clear();
  1381 +
  1382 + // Continue only if node is valid
  1383 + if (node != NULL) {
  1384 +
  1385 + // Get name node and extract text content
  1386 + const GXmlNode* ptr = node->element("name", 0);
  1387 + if (ptr != NULL) {
  1388 + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]);
  1389 + if (text != NULL) {
  1390 + name = text->text();
  1391 + }
  1392 + }
  1393 +
  1394 + // Get value node and extract text content
  1395 + ptr = node->element("value", 0);
  1396 + if (ptr != NULL) {
  1397 + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]);
  1398 + if (text != NULL) {
  1399 + value = text->text();
  1400 + }
  1401 + }
  1402 + }
  1403 +
  1404 + // Return
  1405 + return;
  1406 +}
  1407 +
  1408 +
  1409 +/***********************************************************************//**
  1410 + * @brief Returns subscriptions from XML document
  1411 + *
  1412 + * @param[in] xml client query XML document.
  1413 + * @return List of subscriptions.
  1414 + ***************************************************************************/
  1415 +std::vector<std::string> GVOHub::get_subscriptions(const GXml& xml) const
  1416 +{
  1417 + // Declare subscriptions
  1418 + std::vector<std::string> subscriptions;
  1419 +
  1420 + // Get the client's private key
  1421 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct");
  1422 + if (node != NULL) {
  1423 + int num = node->elements("member");
  1424 + for (int i = 0; i < num; ++i) {
  1425 + const GXmlNode* member = node->element("member", i);
  1426 + if (member != NULL) {
  1427 + const GXmlNode* name = member->element("name", 0);
  1428 + if (name != NULL) {
  1429 + const GXmlText* text = static_cast<const GXmlText*>((*name)[0]);
  1430 + if (text != NULL) {
  1431 + subscriptions.push_back(text->text());
  1432 + }
  1433 + }
  1434 + }
  1435 + }
  1436 + }
  1437 +
  1438 + // Return subscriptions
  1439 + return subscriptions;
  1440 +}
  1441 +
  1442 +
  1443 +/***********************************************************************//**
  1444 + * @brief Returns callback URL of client
  1445 + *
  1446 + * @param[in] xml client query XML document.
  1447 + * @return Callback URL of client.
  1448 + ***************************************************************************/
  1449 +std::string GVOHub::get_callback_url(const GXml& xml) const
  1450 +{
  1451 + // Declare URL
  1452 + std::string url;
  1453 +
  1454 + // Get the client's private key
  1455 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value");
  1456 + if (node != NULL) {
  1457 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  1458 + if (text != NULL) {
  1459 + url.append(text->text());
  1460 + }
  1461 + }
  1462 +
  1463 + // Return URL
  1464 + return url;
  1465 +}
  1466 +
  1467 +
  1468 +/***********************************************************************//**
  1469 + * @brief Returns SAMP Hub lockfile URL
  1470 + *
  1471 + * @return SAMP Hub lockfile URL (empty if no lockfile was found).
  1472 + *
  1473 + * Implements IVOA standard REC-SAMP-1.3-20120411.
  1474 + ***************************************************************************/
  1475 +std::string GVOHub::get_hub_lockfile(void) const
  1476 +{
  1477 + // Initialise result
  1478 + std::string url = "";
  1479 +
  1480 + // Check for existence of the SAMP_HUB environment variable first
  1481 + char* hub_ptr = std::getenv("SAMP_HUB");
  1482 + if (hub_ptr != NULL) {
  1483 +
  1484 + // Check for mandatory std-lockurl: prefix (no other prefixe is
  1485 + // supported so far)
  1486 + std::string lockurl = std::string(hub_ptr);
  1487 + if (lockurl.compare(0, 12, "std-lockurl:") == 0) {
  1488 +
  1489 + // Extract URL
  1490 + url = lockurl.substr(12, std::string::npos);
  1491 +
  1492 + } // endif: std-lockurl: prefix found
  1493 +
  1494 + }
  1495 +
  1496 + // ... otherwise the lockfile should be $HOME/.samp
  1497 + else {
  1498 +
  1499 + // Get user's HOME directory path as the prefix of the full
  1500 + // path. If the HOME environment variable is not set we
  1501 + // expect that .samp is in the local directory. This is non
  1502 + // standard, but prevents for creating an exception here.
  1503 + std::string prefix = "";
  1504 + char* home_ptr = std::getenv("HOME");
  1505 + if (home_ptr != NULL) {
  1506 + prefix = std::string(home_ptr) + "/";
  1507 + }
  1508 +
  1509 + // Set filename
  1510 + url = prefix + ".samp";
  1511 +
  1512 + } // endelse: no SAMP_HUB environment variable found
  1513 +
  1514 + // Return URL
  1515 + return url;
  1516 +}
  1517 +
  1518 +
  1519 +/***********************************************************************//**
  1520 + * @brief Send notifications
  1521 + *
  1522 + * @param[in] method Name of the method
  1523 + * @param[in] client Reference of the client
  1524 + *
  1525 + * The method send notifications to all registered clients that request so.
  1526 + ***************************************************************************/
  1527 +void GVOHub::send_notifications(const std::string& method,
  1528 + const std::string& client)
  1529 +{
  1530 + // Loop over all clients
  1531 + for (int i = 0; i < m_clients.size(); ++i) {
  1532 +
  1533 + // Loop over all methods
  1534 + for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {
  1535 +
  1536 + // Continue only if method matches
  1537 + if (method == m_clients[i].subscriptions[j]) {
  1538 +
  1539 + // Declare notification
  1540 + std::string msg = "";
  1541 +
  1542 + // Register
  1543 + if (method == "samp.hub.event.register") {
  1544 +
  1545 + // Set response for samp.hub.event.register
  1546 + msg.append("<?xml version=\"1.0\"?>\n");
  1547 + msg.append("<methodCall>\n");
  1548 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  1549 + msg.append("<params>\n");
  1550 + msg.append(" <param><value>");
  1551 + msg.append(m_clients[i].private_key);
  1552 + msg.append("</value></param>\n");
  1553 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1554 + msg.append(" <param><value><struct>\n");
  1555 + msg.append(" <member>\n");
  1556 + msg.append(" <name>samp.mtype</name>\n");
  1557 + msg.append(" <value>samp.hub.event.register</value>\n");
  1558 + msg.append(" </member>\n");
  1559 + msg.append(" <member>\n");
  1560 + msg.append(" <name>samp.params</name>\n");
  1561 + msg.append(" <value><struct>\n");
  1562 + msg.append(" <member>\n");
  1563 + msg.append(" <name>id</name>\n");
  1564 + msg.append(" <value>"+client+"</value>\n");
  1565 + msg.append(" </member>\n");
  1566 + msg.append(" </struct></value>\n");
  1567 + msg.append(" </member>\n");
  1568 + msg.append(" </struct></value></param>\n");
  1569 + msg.append("</params>\n");
  1570 + msg.append("</methodCall>\n");
  1571 +
  1572 + // Post notification
  1573 + notify(m_clients[i].url, msg);
  1574 +
  1575 + }
  1576 +
  1577 + // Unregister
  1578 + else if (method == "samp.hub.event.unregister") {
  1579 +
  1580 + // Set response for samp.hub.event.unregister
  1581 + msg.append("<?xml version=\"1.0\"?>\n");
  1582 + msg.append("<methodCall>\n");
  1583 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  1584 + msg.append("<params>\n");
  1585 + msg.append(" <param><value>");
  1586 + msg.append(m_clients[i].private_key);
  1587 + msg.append("</value></param>\n");
  1588 + msg.append(" <param><value>");
  1589 + msg.append(m_hub_id);
  1590 + msg.append("</value></param>\n");
  1591 + msg.append(" <param><value><struct>\n");
  1592 + msg.append(" <member>\n");
  1593 + msg.append(" <name>samp.mtype</name>\n");
  1594 + msg.append(" <value>samp.hub.event.unregister</value>\n");
  1595 + msg.append(" </member>\n");
  1596 + msg.append(" <member>\n");
  1597 + msg.append(" <name>samp.params</name>\n");
  1598 + msg.append(" <value><struct>\n");
  1599 + msg.append(" <member>\n");
  1600 + msg.append(" <name>id</name>\n");
  1601 + msg.append(" <value>"+client+"</value>\n");
  1602 + msg.append(" </member>\n");
  1603 + msg.append(" </struct></value>\n");
  1604 + msg.append(" </member>\n");
  1605 + msg.append(" </struct></value></param>\n");
  1606 + msg.append("</params>\n");
  1607 + msg.append("</methodCall>\n");
  1608 +
  1609 + // Post notification
  1610 + notify(m_clients[i].url, msg);
  1611 +
  1612 + }
  1613 +
  1614 + // Metadata
  1615 + else if (method == "samp.hub.event.metadata") {
  1616 +
  1617 + // Get index of client
  1618 + int k;
  1619 + for (k = 0; k < m_clients.size(); ++k) {
  1620 + if (m_clients[k].reference == client) {
  1621 + break;
  1622 + }
  1623 + }
  1624 +
  1625 + // Fall through if client index is not valid
  1626 + if (k >= m_clients.size()) {
  1627 + continue;
  1628 + }
  1629 +
  1630 + // Set response for samp.hub.event.metadata
  1631 + msg.append("<?xml version=\"1.0\"?>\n");
  1632 + msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
  1633 + msg.append("<params>\n");
  1634 + msg.append(" <param><value>");
  1635 + msg.append(m_clients[i].private_key);
  1636 + msg.append("</value></param>\n");
  1637 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1638 + msg.append(" <param><value><struct>\n");
  1639 + msg.append(" <member>\n");
  1640 + msg.append(" <name>samp.mtype</name>\n");
  1641 + msg.append(" <value>samp.hub.event.metadata</value>\n");
  1642 + msg.append(" </member>\n");
  1643 + msg.append(" <member>\n");
  1644 + msg.append(" <name>samp.params</name>\n");
  1645 + msg.append(" <value><struct>\n");
  1646 + msg.append(" <member>\n");
  1647 + msg.append(" <name>id</name>\n");
  1648 + msg.append(" <value>"+m_clients[k].reference+"</value>\n");
  1649 + msg.append(" </member>\n");
  1650 + msg.append(" <member>\n");
  1651 + msg.append(" <name>metadata</name>\n");
  1652 + msg.append(" <value><struct>\n");
  1653 + msg.append(" <member>\n");
  1654 + msg.append(" <name>samp.name</name>\n");
  1655 + msg.append(" <value>"+m_clients[k].name+"</value>\n");
  1656 + msg.append(" </member>\n");
  1657 + msg.append(" <member>\n");
  1658 + msg.append(" <name>samp.description.text</name>\n");
  1659 + msg.append(" <value>"+m_clients[k].description+"</value>\n");
  1660 + msg.append(" </member>\n");
  1661 + msg.append(" <member>\n");
  1662 + msg.append(" <name>samp.icon.url</name>\n");
  1663 + msg.append(" <value>"+m_clients[k].icon+"</value>\n");
  1664 + msg.append(" </member>\n");
  1665 + msg.append(" <member>\n");
  1666 + msg.append(" <name>samp.documentation.url</name>\n");
  1667 + msg.append(" <value>"+m_clients[k].documentation+"</value>\n");
  1668 + msg.append(" </member>\n");
  1669 + msg.append(" <member>\n");
  1670 + msg.append(" <name>author.affiliation</name>\n");
  1671 + msg.append(" <value>"+m_clients[k].affiliation+"</value>\n");
  1672 + msg.append(" </member>\n");
  1673 + msg.append(" <member>\n");
  1674 + msg.append(" <name>author.name</name>\n");
  1675 + msg.append(" <value>"+m_clients[k].author_name+"</value>\n");
  1676 + msg.append(" </member>\n");
  1677 + msg.append(" <member>\n");
  1678 + msg.append(" <name>author.email</name>\n");
  1679 + msg.append(" <value>"+m_clients[k].email+"</value>\n");
  1680 + msg.append(" </member>\n");
  1681 + msg.append(" <member>\n");
  1682 + msg.append(" <name>home.page</name>\n");
  1683 + msg.append(" <value>"+m_clients[k].homepage+"</value>\n");
  1684 + msg.append(" </member>\n");
  1685 + msg.append(" </struct></value>\n");
  1686 + msg.append(" </member>\n");
  1687 + msg.append(" </struct></value>\n");
  1688 + msg.append(" </member>\n");
  1689 + msg.append(" </struct></value></param>\n");
  1690 + msg.append("</params>\n");
  1691 + msg.append("</methodCall>\n");
  1692 +
  1693 + // Post notification
  1694 + notify(m_clients[i].url, msg);
  1695 +
  1696 + } // endelse: metadata
  1697 +
  1698 + } // endif: method was requested one
  1699 +
  1700 + } // endfor: looped over all methods
  1701 +
  1702 + } // endfor: looped over all clients
  1703 +
  1704 + // Return
  1705 + return;
  1706 +}
  1707 +
  1708 +
  1709 +/***********************************************************************//**
  1710 + * @brief Creates the lockfile, fill it
  1711 + *
  1712 + * Implements IVOA standard REC-SAMP-1.3-20120411.
  1713 + ***************************************************************************/
  1714 +void GVOHub::create_samp_file(void) const
  1715 +{
  1716 + // Get lockfile URL
  1717 + std::string lockurl = get_hub_lockfile();
  1718 +
  1719 + // Open SAMP lockfile. Continue only if opening was successful
  1720 + FILE* fptr = fopen(lockurl.c_str(), "w");
  1721 +
  1722 + // Successful?
  1723 + if (fptr != NULL) {
  1724 +
  1725 + // Write lockfile
  1726 + fprintf(fptr, "# SAMP lockfile\n");
  1727 + fprintf(fptr, "# Required keys:\n");
  1728 + fprintf(fptr, "samp.secret=%s\n", m_secret.c_str());
  1729 + fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", m_hub_url.c_str());
  1730 + fprintf(fptr, "samp.profile.version=%s\n", m_version.c_str());
  1731 + fprintf(fptr, "# Info stored by hub for some private reason:\n");
  1732 + fprintf(fptr, "gammalib.hubid=%s\n", m_hub_id.c_str());
  1733 +
  1734 + // Close lockfile
  1735 + fclose(fptr);
  1736 +
  1737 + }
  1738 +
  1739 + // Return
  1740 + return;
  1741 +}
  1742 +
  1743 +
  1744 +/***********************************************************************//**
  1745 + * @brief Post string content to client
  1746 + *
  1747 + * @param[in] content String content to post.
  1748 + * @param[in] sock Socket.
  1749 + *
  1750 + * Posts the content of a string to a client.
  1751 + ***************************************************************************/
  1752 +void GVOHub::post_string(const std::string& content, const socklen_t& sock) const
  1753 +{
  1754 + // Continue only if socket is valid
  1755 + if (sock != -1) {
  1756 +
  1757 + // Determine content length
  1758 + int length = content.length();
  1759 +
  1760 + // Set prefix (note that the response has no POST!)
  1761 + std::string prefix = "HTTP/1.1 200 OK\n"
  1762 + "Connection: close\n"
  1763 + "Content-Type: text/xml\n"
  1764 + "Content-Length: "+gammalib::str(length)+"\n\n";
  1765 +
  1766 +
  1767 + // Build post string
  1768 + std::string post = prefix + content;
  1769 +
  1770 + // Dump message to post
  1771 + #if defined(G_SHOW_MESSAGE)
  1772 + std::cout << std::endl;
  1773 + std::cout << "GVOHub response:" << std::endl;
  1774 + std::cout << "================" << std::endl;
  1775 + std::cout << post << std::endl;
  1776 + #endif
  1777 +
  1778 + // Send content to socket
  1779 + bool done = false;
  1780 + do {
  1781 + int length = post.length();
  1782 + int sent_length = send(sock, post.c_str(), length, 0);
  1783 + if (sent_length < length) {
  1784 + post = post.substr(sent_length, std::string::npos);
  1785 + }
  1786 + else {
  1787 + done = true;
  1788 + }
  1789 + } while (!done);
  1790 +
  1791 + } // endif: socket was valid
  1792 +
  1793 + // Return
  1794 + return;
  1795 +}
  1796 +
  1797 +
  1798 +/***********************************************************************//**
  1799 + * @brief Post SAMP ok massage to client
  1800 + *
  1801 + * @param[in] sock Socket.
  1802 + *
  1803 + * Posts a SAMP OK message to a client.
  1804 + ***************************************************************************/
  1805 +void GVOHub::post_samp_ok(const socklen_t& sock) const
  1806 +{
  1807 + // Declare response
  1808 + std::string response = "";
  1809 +
  1810 + // Compose response
  1811 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  1812 + response.append("<methodResponse>\n");
  1813 + response.append("<params>\n");
  1814 + response.append(" <param><value><struct>\n");
  1815 + response.append(" <member>\n");
  1816 + response.append(" <name>samp.status</name>\n");
  1817 + response.append(" <value>samp.ok</value>\n");
  1818 + response.append(" </member>\n");
  1819 + response.append(" </struct></value></param>\n");
  1820 + response.append("</params>\n");
  1821 + response.append("</methodResponse>\n");
  1822 +
  1823 + // Post string
  1824 + post_string(response, sock);
  1825 +
  1826 + // Return
  1827 + return;
  1828 +}
  1829 +
  1830 +
  1831 +/***********************************************************************//**
  1832 + * @brief Post SAMP void massage to client
  1833 + *
  1834 + * @param[in] sock Socket.
  1835 + *
  1836 + * Posts a void SAMP message to a client. Void messages can typically be
  1837 + * discared by the client.
  1838 + ***************************************************************************/
  1839 +void GVOHub::post_samp_void(const socklen_t& sock) const
  1840 +{
  1841 + // Declare response
  1842 + std::string response = "";
  1843 +
  1844 + // Compose response
  1845 + response.append("<?xml version='1.0' encoding='UTF-8'?>\n");
  1846 + response.append("<methodResponse>\n");
  1847 + response.append(" <params>\n");
  1848 + response.append(" <param>\n");
  1849 + response.append(" <value/>\n");
  1850 + response.append(" </param>\n");
  1851 + response.append(" </params>\n");
  1852 + response.append("</methodResponse>\n");
  1853 +
  1854 + // Post string
  1855 + post_string(response, sock);
  1856 +
  1857 + // Return
  1858 + return;
  1859 +}
  1860 +
  1861 +
  1862 +/***********************************************************************//**
  1863 + * @brief Send notification to client
  1864 + *
  1865 + * @param[in] url URL.
  1866 + * @param[in] notification Notification.
  1867 + *
  1868 + * Send a @p notification to a @p url.
  1869 + ***************************************************************************/
  1870 +void GVOHub::notify(const std::string& url,
  1871 + const std::string& notification) const
  1872 +{
  1873 + // Initalise socket
  1874 + int socket = -1;
  1875 +
  1876 + // Extract host, port and path from URL
  1877 + std::string host = "127.0.0.1";
  1878 + std::string port = "2525";
  1879 + std::string path = "xmlrpc";
  1880 + if (url.compare(0, 7, "http://") == 0) {
  1881 + size_t length;
  1882 + size_t start = 7;
  1883 + size_t stop = url.find(":", start);
  1884 + size_t end = std::string::npos;
  1885 + if (stop != std::string::npos) {
  1886 + length = stop - start;
  1887 + }
  1888 + else {
  1889 + length = std::string::npos;
  1890 + }
  1891 + host = url.substr(start, length);
  1892 + if (stop != std::string::npos) {
  1893 + stop++;
  1894 + end = url.find("/", stop);
  1895 + if (end != std::string::npos) {
  1896 + length = end - stop;
  1897 + }
  1898 + else {
  1899 + length = std::string::npos;
  1900 + }
  1901 + port = url.substr(stop, length);
  1902 + }
  1903 + if (end != std::string::npos) {
  1904 + end++;
  1905 + length = url.length() - end;
  1906 + path = url.substr(end, length);
  1907 + }
  1908 + }
  1909 +
  1910 + // Set hints
  1911 + struct addrinfo hints;
  1912 + std::memset(&hints, 0, sizeof(hints));
  1913 + hints.ai_family = AF_INET;
  1914 + hints.ai_socktype = SOCK_STREAM;
  1915 +
  1916 + // Get server information
  1917 + struct addrinfo* servinfo;
  1918 + if (getaddrinfo(host.c_str(), port.c_str(), &hints, &servinfo) == 0) {
  1919 +
  1920 + // Loop through all the results and connect to the first we can
  1921 + for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) {
  1922 +
  1923 + // Create socket
  1924 + socket = ::socket(ptr->ai_family,
  1925 + ptr->ai_socktype,
  1926 + ptr->ai_protocol);
  1927 +
  1928 + // Connect to socket if socket is valid
  1929 + if (socket != -1) {
  1930 + if (::connect(socket,
  1931 + ptr->ai_addr,
  1932 + ptr->ai_addrlen) == -1) {
  1933 + close(socket);
  1934 + socket = -1;
  1935 + }
  1936 + else {
  1937 + // Socket connection successful, break now
  1938 + break;
  1939 + }
  1940 + }
  1941 +
  1942 + } // endfor: looped through all results
  1943 +
  1944 + } // endif: server information was valid
  1945 +
  1946 + // Continue only if socket is valid
  1947 + if (socket != -1) {
  1948 +
  1949 + // Determine notification length
  1950 + int length = notification.length();
  1951 +
  1952 + // Set prefix
  1953 + std::string prefix = "POST /"+path+" HTTP/1.0\n"
  1954 + "Connection: close\n"
  1955 + "User-Agent: GammaLib\n"
  1956 + "Content-Type: text/xml\n"
  1957 + "Content-Length: "+gammalib::str(length)+"\n\n";
  1958 +
  1959 + // Build post string
  1960 + std::string post = prefix + notification;
  1961 +
  1962 + // Dump message to post
  1963 + #if defined(G_SHOW_MESSAGE)
  1964 + std::cout << std::endl;
  1965 + std::cout << "GVOHub sends following notification:" << std::endl;
  1966 + std::cout << "====================================" << std::endl;
  1967 + std::cout << post << std::endl;
  1968 + #endif
  1969 +
  1970 + // Send content to socket
  1971 + bool done = false;
  1972 + do {
  1973 + int length = post.length() + 1; // +1 for terminating 0
  1974 + int sent_length = send(socket, post.c_str(), length, 0);
  1975 + if (sent_length < length) {
  1976 + post = post.substr(sent_length, std::string::npos);
  1977 + }
  1978 + else {
  1979 + done = true;
  1980 + }
  1981 + } while (!done);
  1982 +
  1983 + /*
  1984 + // Declare response
  1985 + std::string response = "";
  1986 +
  1987 + // Read buffer until it is empty
  1988 + char buffer[1001];
  1989 + int timeout = 1000; // Initial timeout is 1 sec
  1990 + int n = 0;
  1991 + do {
  1992 + n = gammalib::recv(socket, buffer, 1000, 0, timeout);
  1993 + if (n > 0) {
  1994 + buffer[n+1] = '\0';
  1995 + response.append(std::string(buffer));
  1996 + }
  1997 + timeout = 10; // The timeout now is 0.01 sec
  1998 + } while (n > 0);
  1999 + */
  2000 +
  2001 + // Close socket
  2002 + close(socket);
  2003 +
  2004 + }
  2005 +
  2006 + // Return
  2007 + return;
  2008 +}
  2009 +
  2010 +
  2011 +/***********************************************************************//**
  2012 + * @brief Generates random string of characters
  2013 + *
  2014 + * @param[in] length Length of random string
  2015 + ***************************************************************************/
  2016 +std::string GVOHub::random_string(const size_t& length) const
  2017 +{
  2018 + srand(time(0));
  2019 + std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  2020 + int pos;
  2021 + while(str.size() != length) {
  2022 + pos = ((rand() % (str.size() - 1)));
  2023 + str.erase (pos, 1);
  2024 + }
  2025 +
  2026 + // Return string
  2027 + return str;
  2028 +}
  2029 +/***********************************************************************//**
  2030 + * @brief Extract mtype from XML request
  2031 + *
  2032 + * @param[in] xml XML message sent by client.
  2033 + *
  2034 + * Extracts the mtype identifying calling message from the XML request.
  2035 + ***************************************************************************/
  2036 +std::string GVOHub::get_mtype(const GXml& xml) const
  2037 +{
  2038 + // Header
  2039 + #if defined(G_CONSOLE_DUMP)
  2040 + std::cout << "GVOHub::get_mtype" << std::endl;
  2041 + #endif
  2042 +
  2043 + // Initialise response
  2044 + std::string client_key = "";
  2045 +
  2046 + // Get the client's private key
  2047 + const GXmlNode* node = xml.element("methodCall > params > param > value");
  2048 + if (node != NULL) {
  2049 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  2050 + if (text != NULL) {
  2051 + client_key = text->text();
  2052 + }
  2053 + }
  2054 +
  2055 + // Return key
  2056 + return client_key;
  2057 +}
  2058 +/***********************************************************************//**
  2059 + * @brief Extract client destination from XML request
  2060 + *
  2061 + * @param[in] xml XML message sent by client.
  2062 + *
  2063 + * Extracts identifier of destination client from the XML request.
  2064 + ***************************************************************************/
  2065 +std::string GVOHub::get_destination(const GXml& xml) const
  2066 +{
  2067 + // Header
  2068 + #if defined(G_CONSOLE_DUMP)
  2069 + std::cout << "GVOHub::get_mtype" << std::endl;
  2070 + #endif
  2071 +
  2072 + // Initialise response
  2073 + std::string client_key = "";
  2074 +
  2075 + // Get the client's private key
  2076 + const GXmlNode* node = xml.element("methodCall > params > param > value");
  2077 + if (node != NULL) {
  2078 + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]);
  2079 + if (text != NULL) {
  2080 + client_key = text->text();
  2081 + }
  2082 + }
  2083 +
  2084 + // Return key
  2085 + return client_key;
  2086 +}
... ...
src/vo/GVOTable.cpp 0 → 100644
  1 +/***************************************************************************
  2 + * GVOTable.cpp - VO Table composition class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2015 by Thierry Louge *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GVOTable.cpp
  23 + * @brief VO Table composition class
  24 + * @author Thierry Louge
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdlib> // std::getenv() function
  32 +#include <cstdio> // std::fopen(), etc. functions
  33 +#include <cstring> // std::memset() function
  34 +#include <csignal> // signal() function
  35 +#include <cerrno> // errno
  36 +#include <unistd.h> // close() function
  37 +#include <netdb.h> // getaddrinfo() function
  38 +#include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons
  39 +#include <fstream>
  40 +#include <sys/shm.h>
  41 +#include <sys/socket.h> // socket(), connect() functions
  42 +#include <sys/wait.h> // waitpid() function
  43 +#include <arpa/inet.h> // inet_addr() function
  44 +#include "GVOTable.hpp"
  45 +#include "GException.hpp"
  46 +#include "GTools.hpp"
  47 +
  48 +/* __ Method name definitions ____________________________________________ */
  49 +
  50 +/* __ Macros _____________________________________________________________ */
  51 +
  52 +/* __ Coding definitions _________________________________________________ */
  53 +
  54 +/* __ Debug definitions __________________________________________________ */
  55 +//#define G_CONSOLE_DUMP
  56 +#define G_SHOW_MESSAGE
  57 +
  58 +
  59 +/*==========================================================================
  60 + = =
  61 + = Constructors/destructors =
  62 + = =
  63 + ==========================================================================*/
  64 +
  65 +/***********************************************************************//**
  66 + * @brief Void constructor
  67 + ***************************************************************************/
  68 +GVOTable::GVOTable(void)
  69 +{
  70 + // Initialise members
  71 + init_members();
  72 +
  73 + // Return
  74 + return;
  75 +}
  76 +
  77 +
  78 +/***********************************************************************//**
  79 + * @brief Copy constructor
  80 + *
  81 + * @param[in] VOTable
  82 + ***************************************************************************/
  83 +GVOTable::GVOTable(const GVOTable& votable)
  84 +{
  85 + // Initialise members
  86 + init_members();
  87 +
  88 + // Copy members
  89 + copy_members(votable);
  90 +
  91 + // Return
  92 + return;
  93 +}
  94 +
  95 +
  96 +/***********************************************************************//**
  97 + * @brief Destructor
  98 + ***************************************************************************/
  99 +GVOTable::~GVOTable(void)
  100 +{
  101 + // Free members
  102 + free_members();
  103 +
  104 + // Return
  105 + return;
  106 +}
  107 +
  108 +
  109 +/*==========================================================================
  110 + = =
  111 + = Operators =
  112 + = =
  113 + ==========================================================================*/
  114 +
  115 +/***********************************************************************//**
  116 + * @brief Assignment operator
  117 + *
  118 + * @param[in] VO table.
  119 + * @return VO table.
  120 + ***************************************************************************/
  121 +GVOTable& GVOTable::operator=(const GVOTable& votable)
  122 +{
  123 + // Execute only if object is not identical
  124 + if (this != &votable) {
  125 +
  126 + // Free members
  127 + free_members();
  128 +
  129 + // Initialise members
  130 + init_members();
  131 +
  132 + // Copy members
  133 + copy_members(votable);
  134 +
  135 + } // endif: object was not identical
  136 +
  137 + // Return
  138 + return *this;
  139 +}
  140 +
  141 +
  142 +/*==========================================================================
  143 + = =
  144 + = Public methods =
  145 + = =
  146 + ==========================================================================*/
  147 +
  148 +/***********************************************************************//**
  149 + * @brief Clear object.
  150 + *
  151 + * Reset object to a clean initial state.
  152 + ***************************************************************************/
  153 +void GVOTable::clear(void)
  154 +{
  155 + // Free members
  156 + free_members();
  157 +
  158 + // Initialise members
  159 + init_members();
  160 +
  161 + // Return
  162 + return;
  163 +}
  164 +
  165 +
  166 +/***********************************************************************//**
  167 + * @brief Clone object
  168 + ***************************************************************************/
  169 +GVOTable* GVOTable::clone(void) const
  170 +{
  171 + // Clone client
  172 + return new GVOTable(*this);
  173 +}
  174 +
  175 +
  176 +/***********************************************************************//**
  177 + * @brief Print VO hub information
  178 + *
  179 + * @param[in] chatter Chattiness (defaults to NORMAL).
  180 + * @return String containing VO table information
  181 + ***************************************************************************/
  182 +std::string GVOTable::print(const GChatter& chatter) const
  183 +{
  184 + // Initialise result string
  185 + std::string result;
  186 +
  187 + // Continue only if chatter is not silent
  188 + if (chatter != SILENT) {
  189 +
  190 + // Append header
  191 + result.append("=== GVOTable ===");
  192 +
  193 + // Append table information
  194 +
  195 + } // endif: chatter was not silent
  196 +
  197 + // Return result
  198 + return result;
  199 +}
  200 +/***********************************************************************//**
  201 + * @brief Creates the VO table, fill it
  202 + *
  203 + * Implements IVOA standard <standard id>
  204 + ***************************************************************************/
  205 +void GVOTable::create_votable(void)
  206 +{
  207 + std::string header = "";
  208 + header.append("<?xml version=\"1.0\"?>\n");
  209 + header.append("<VOTABLE version=\"1.3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
  210 + header.append("xmlns=\"http://www.ivoa.net/xml/VOTable/v1.3\"\n");
  211 + //Change this with relevant datamodel
  212 + header.append("xmlns:stc=\"http://www.ivoa.net/xml/STC/v1.30\">\n");
  213 + header.append("\t<RESOURCE name=\"GammalibSkymap\">\n");
  214 + header.append("\t\t<TABLE name=\"skymap\">\n");
  215 + header.append("\t\t\t<DESCRIPTION>Skymap coming from gammalib</DESCRIPTION>\n");
  216 + //Only for testing, we close the document.
  217 + header.append("\t\t</TABLE>\n");
  218 + header.append("\t</RESOURCE>\n");
  219 + header.append("</VOTABLE>\n");
  220 +
  221 + m_tablexml = GXml(header);
  222 + m_tablexml.print(NORMAL,0);
  223 + // Return
  224 + return;
  225 +}
  226 +
  227 +
  228 +/***********************************************************************//**
  229 + * @brief Fills content of the VO table
  230 + *
  231 + * Implements IVOA standard <standard id>
  232 + ***************************************************************************/
  233 +void GVOTable::fill_content(const std::string& data) const
  234 +{
  235 +
  236 + // Return
  237 + return;
  238 +}
  239 +
  240 +/*==========================================================================
  241 + = =
  242 + = Private methods =
  243 + = =
  244 + ==========================================================================*/
  245 +
  246 +/***********************************************************************//**
  247 + * @brief Initialise class members
  248 + ***************************************************************************/
  249 +void GVOTable::init_members(void)
  250 +{
  251 + // Initialise members
  252 +
  253 + // Return
  254 + return;
  255 +}
  256 +
  257 +
  258 +/***********************************************************************//**
  259 + * @brief Copy class members
  260 + *
  261 + * @param[in] hub VO hub.
  262 + ***************************************************************************/
  263 +void GVOTable::copy_members(const GVOTable& hub)
  264 +{
  265 + // Copy members
  266 +
  267 + // Return
  268 + return;
  269 +}
  270 +
  271 +
  272 +/***********************************************************************//**
  273 + * @brief Delete class members
  274 + ***************************************************************************/
  275 +void GVOTable::free_members(void)
  276 +{
  277 +
  278 + // Return
  279 + return;
  280 +}
  281 +
... ...
src/vo/GVOTable.cpp~ 0 → 100644
  1 +/***************************************************************************
  2 + * GVOTable.cpp - VO Table composition class *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2015 by Thierry Louge *
  5 + * ----------------------------------------------------------------------- *
  6 + * *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  19 + * *
  20 + ***************************************************************************/
  21 +/**
  22 + * @file GVOTable.cpp
  23 + * @brief VO Table composition class
  24 + * @author Thierry Louge
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdlib> // std::getenv() function
  32 +#include <cstdio> // std::fopen(), etc. functions
  33 +#include <cstring> // std::memset() function
  34 +#include <csignal> // signal() function
  35 +#include <cerrno> // errno
  36 +#include <unistd.h> // close() function
  37 +#include <netdb.h> // getaddrinfo() function
  38 +#include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons
  39 +#include <fstream>
  40 +#include <sys/shm.h>
  41 +#include <sys/socket.h> // socket(), connect() functions
  42 +#include <sys/wait.h> // waitpid() function
  43 +#include <arpa/inet.h> // inet_addr() function
  44 +#include "GVOTable.hpp"
  45 +#include "GException.hpp"
  46 +#include "GTools.hpp"
  47 +
  48 +/* __ Method name definitions ____________________________________________ */
  49 +
  50 +/* __ Macros _____________________________________________________________ */
  51 +
  52 +/* __ Coding definitions _________________________________________________ */
  53 +
  54 +/* __ Debug definitions __________________________________________________ */
  55 +//#define G_CONSOLE_DUMP
  56 +#define G_SHOW_MESSAGE
  57 +
  58 +
  59 +/*==========================================================================
  60 + = =
  61 + = Constructors/destructors =
  62 + = =
  63 + ==========================================================================*/
  64 +
  65 +/***********************************************************************//**
  66 + * @brief Void constructor
  67 + ***************************************************************************/
  68 +GVOTable::GVOTable(void)
  69 +{
  70 + // Initialise members
  71 + init_members();
  72 +
  73 + // Return
  74 + return;
  75 +}
  76 +
  77 +
  78 +/***********************************************************************//**
  79 + * @brief Copy constructor
  80 + *
  81 + * @param[in] VOTable
  82 + ***************************************************************************/
  83 +GVOTable::GVOTable(const GVOTable& votable)
  84 +{
  85 + // Initialise members
  86 + init_members();
  87 +
  88 + // Copy members
  89 + copy_members(votable);
  90 +
  91 + // Return
  92 + return;
  93 +}
  94 +
  95 +
  96 +/***********************************************************************//**
  97 + * @brief Destructor
  98 + ***************************************************************************/
  99 +GVOTable::~GVOTable(void)
  100 +{
  101 + // Free members
  102 + free_members();
  103 +
  104 + // Return
  105 + return;
  106 +}
  107 +
  108 +
  109 +/*==========================================================================
  110 + = =
  111 + = Operators =
  112 + = =
  113 + ==========================================================================*/
  114 +
  115 +/***********************************************************************//**
  116 + * @brief Assignment operator
  117 + *
  118 + * @param[in] VO table.
  119 + * @return VO table.
  120 + ***************************************************************************/
  121 +GVOTable& GVOTable::operator=(const GVOTable& votable)
  122 +{
  123 + // Execute only if object is not identical
  124 + if (this != &votable) {
  125 +
  126 + // Free members
  127 + free_members();
  128 +
  129 + // Initialise members
  130 + init_members();
  131 +
  132 + // Copy members
  133 + copy_members(votable);
  134 +
  135 + } // endif: object was not identical
  136 +
  137 + // Return
  138 + return *this;
  139 +}
  140 +
  141 +
  142 +/*==========================================================================
  143 + = =
  144 + = Public methods =
  145 + = =
  146 + ==========================================================================*/
  147 +
  148 +/***********************************************************************//**
  149 + * @brief Clear object.
  150 + *
  151 + * Reset object to a clean initial state.
  152 + ***************************************************************************/
  153 +void GVOTable::clear(void)
  154 +{
  155 + // Free members
  156 + free_members();
  157 +
  158 + // Initialise members
  159 + init_members();
  160 +
  161 + // Return
  162 + return;
  163 +}
  164 +
  165 +
  166 +/***********************************************************************//**
  167 + * @brief Clone object
  168 + ***************************************************************************/
  169 +GVOTable* GVOTable::clone(void) const
  170 +{
  171 + // Clone client
  172 + return new GVOTable(*this);
  173 +}
  174 +
  175 +
  176 +/***********************************************************************//**
  177 + * @brief Print VO hub information
  178 + *
  179 + * @param[in] chatter Chattiness (defaults to NORMAL).
  180 + * @return String containing VO table information
  181 + ***************************************************************************/
  182 +std::string GVOTable::print(const GChatter& chatter) const
  183 +{
  184 + // Initialise result string
  185 + std::string result;
  186 +
  187 + // Continue only if chatter is not silent
  188 + if (chatter != SILENT) {
  189 +
  190 + // Append header
  191 + result.append("=== GVOTable ===");
  192 +
  193 + // Append table information
  194 +
  195 + } // endif: chatter was not silent
  196 +
  197 + // Return result
  198 + return result;
  199 +}
  200 +/***********************************************************************//**
  201 + * @brief Creates the VO table, fill it
  202 + *
  203 + * Implements IVOA standard <standard id>
  204 + ***************************************************************************/
  205 +void GVOTable::create_votable(void)
  206 +{
  207 + std::string header = "";
  208 + header.append("<?xml version=\"1.0\"?>\n");
  209 + header.append("<VOTABLE version=\"1.3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
  210 + header.append("xmlns=\"http://www.ivoa.net/xml/VOTable/v1.3\"\n");
  211 + //Change this with relevant datamodel
  212 + header.append("xmlns:stc=\"http://www.ivoa.net/xml/STC/v1.30\">\n");
  213 + header.append("\t<RESOURCE name=\"GammalibSkymap\">\n");
  214 + header.append("\t\t<TABLE name=\"skymap\">\n");
  215 + header.append("\t\t\t<DESCRIPTION>Sloaded_map = skymap.load("kymap coming from gammalib</DESCRIPTION>\n");
  216 + //Only for testing, we close the document.
  217 + header.append("\t\t</TABLE>\n");
  218 + header.append("\t</RESOURCE>\n");
  219 + header.append("</VOTABLE>\n");
  220 +
  221 + m_tablexml = GXml(header);
  222 + m_tablexml.print(NORMAL,0);
  223 + // Return
  224 + return;
  225 +}
  226 +
  227 +
  228 +/***********************************************************************//**
  229 + * @brief Fills content of the VO table
  230 + *
  231 + * Implements IVOA standard <standard id>
  232 + ***************************************************************************/
  233 +void GVOTable::fill_content(const std::string& data) const
  234 +{
  235 +
  236 + // Return
  237 + return;
  238 +}
  239 +
  240 +/*==========================================================================
  241 + = =
  242 + = Private methods =
  243 + = =
  244 + ==========================================================================*/
  245 +
  246 +/***********************************************************************//**
  247 + * @brief Initialise class members
  248 + ***************************************************************************/
  249 +void GVOTable::init_members(void)
  250 +{
  251 + // Initialise members
  252 +
  253 + // Return
  254 + return;
  255 +}
  256 +
  257 +
  258 +/***********************************************************************//**
  259 + * @brief Copy class members
  260 + *
  261 + * @param[in] hub VO hub.
  262 + ***************************************************************************/
  263 +void GVOTable::copy_members(const GVOTable& hub)
  264 +{
  265 + // Copy members
  266 +
  267 + // Return
  268 + return;
  269 +}
  270 +
  271 +
  272 +/***********************************************************************//**
  273 + * @brief Delete class members
  274 + ***************************************************************************/
  275 +void GVOTable::free_members(void)
  276 +{
  277 +
  278 + // Return
  279 + return;
  280 +}
  281 +
... ...
src/vo/Makefile.am
... ... @@ -7,7 +7,8 @@ INCLUDES = -I$(top_srcdir)/include \
7 7  
8 8 # Define sources for this directory
9 9 sources = GVOClient.cpp \
10   - GVOHub.cpp
  10 + GVOHub.cpp \
  11 + GVOTable.cpp
11 12  
12 13 # Build libtool library
13 14 noinst_LTLIBRARIES = libvo.la
... ...