Hash :
6df4dcf4
Author :
Date :
2014-10-22T09:22:43
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
;;
;; adams - Remote system administration tools
;;
;; Copyright 2013 Thomas de Grivel <billitch@gmail.com>
;;
;; Permission to use, copy, modify, and distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.
;;
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
;;
(in-package :adams)
(unless (boundp '+undefined+)
(defconstant +undefined+ '#:undefined))
;; Probe
(defclass probe ()
((name :initarg :name
:initform (error "Probe without a name.")
:reader probe-name
:type symbol)
(properties :initarg :properties
:initform (error "Probe without properties.")
:reader probe-properties)))
(defgeneric probe-generic-function (probe))
(defmethod probe-generic-function ((probe probe))
(symbol-function (probe-name probe)))
(defmethod print-object ((probe probe) stream)
(print-unreadable-object (probe stream :type t :identity (not *print-pretty*))
(format stream "~S (~{~A~^ ~})"
(probe-name probe)
(probe-properties probe))))
;; Resource meta class
(defvar *the-resource-class*)
(defclass resource-class (standard-class)
((direct-probes :initarg :direct-probes
:initform ()
:reader resource-class-direct-probes
:type list)
(probes :initarg :direct-probes
:initform ()
:reader resource-class-probes
:type list))
(:default-initargs :direct-superclasses (list *the-resource-class*)))
(defmethod closer-mop:validate-superclass ((class resource-class)
(super standard-class))
t)
(defgeneric resource-class-probe-class (resource-class))
(defmethod resource-class-probe-class ((resource-class resource-class))
'probe)
(defgeneric compute-probes (resource-class))
(defmethod compute-probes ((resource-class resource-class))
(iter (for class in (closer-mop:class-precedence-list resource-class))
(for direct-probes = (when (typep class 'resource-class)
(resource-class-direct-probes class)))
(dolist (probe-definition direct-probes)
(collect (apply #'make-instance
(resource-class-probe-class resource-class)
:name probe-definition)))))
(defmethod closer-mop:finalize-inheritance :after ((resource-class resource-class))
(setf (slot-value resource-class 'probes)
(compute-probes resource-class)))
(defmacro define-resource-class (name direct-superclasses
direct-slots direct-probes
&optional options)
`(defclass ,name ,(or direct-superclasses
'(resource))
,direct-slots
(:metaclass resource-class)
(:direct-probes ,@direct-probes)
,@options))
;; Resources
(defclass resource (standard-object)
((id :type atom
:initarg :id
:initform (error "Missing ID for resource.")
:reader resource-id)
(specified-properties :type list
:initarg :specified-properties
:initform nil
:reader specified-properties)
(probed-properties :type list
:initarg :probed-properties
:initform nil
:reader probed-properties))
(:metaclass resource-class))
(setq *the-resource-class* (find-class 'resource))
(defmethod print-object ((res resource) stream)
(print-unreadable-object (res stream :type t :identity *print-readably*)
(format stream "~S ~D ~D" (resource-id res)
(/ (length (specified-properties res)) 2)
(/ (length (probed-properties res)) 2))))
;; Probes
(defun os-class (os)
(etypecase os
(null t)
((eql t) t)
(symbol (find-class os))
(os (class-of os))
(standard-class os)))
(defgeneric find-probe (resource property os))
(defmethod find-probe ((resource resource)
(property symbol)
os)
(some (lambda (probe)
(when (find property (probe-properties probe) :test #'eq)
(let ((f (probe-generic-function probe)))
(when (compute-applicable-methods f (list resource os))
f))))
(resource-class-probes (class-of resource))))
(defgeneric probe (resource property))
(defmethod probe ((resource resource) (property symbol))
(with-slots (probed-properties) resource
(let* ((os (os))
(probe (or (find-probe resource property os)
(error "No probe found for ~S property ~S on ~A"
resource property (class-name (class-of os)))))
(result (funcall probe resource os)))
(when (eq +undefined+ (getf result property +undefined+))
(error "Probe did not return expected property.~%~
resource: ~S~%~
property: ~S~%~
probe: ~S~%~
result: ~S"
resource property probe result))
(setf probed-properties
(append result probed-properties))
result)))
(defgeneric get-probed (resource property))
(defmethod get-probed ((resource resource) (property symbol))
(let ((value (getf (probed-properties resource) property +undefined+)))
(when (eq +undefined+ value)
(setq value (getf (probe resource property) property +undefined+)))
(when (eq +undefined+ value)
(error "Probe did not return expected property."))
value))
(defun make-resource (type id &rest initargs &key &allow-other-keys)
(apply #'make-instance type :id id initargs))