1/*
2 * Copyright (c) 2015, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30#include "ElementHandle.h"
31#include "ParameterAccessContext.h"
32#include "BaseParameter.h"
33#include "XmlParameterSerializingContext.h"
34#include "Subsystem.h"
35#include <assert.h>
36#include "ParameterMgr.h"
37
38#include <mutex>
39
40using std::string;
41using std::mutex;
42using std::lock_guard;
43
44/** @return 0 by default, ie for non overloaded types. */
45template <class T>
46static size_t getUserInputSize(const T & /*scalar*/)
47{
48    return 0;
49}
50
51/** @return the vector's size. */
52template <class T>
53static size_t getUserInputSize(const std::vector<T> &vector)
54{
55    return vector.size();
56}
57
58ElementHandle::ElementHandle(CConfigurableElement &element, CParameterMgr &parameterMgr)
59    : mElement(element), mParameterMgr(parameterMgr)
60{
61}
62
63string ElementHandle::getName() const
64{
65    return mElement.getName();
66}
67
68size_t ElementHandle::getSize() const
69{
70    return mElement.getFootPrint();
71}
72
73bool ElementHandle::isParameter() const
74{
75    return mElement.isParameter();
76}
77
78string ElementHandle::getDescription() const
79{
80    return mElement.getDescription();
81}
82
83// Parameter features
84bool ElementHandle::isRogue() const
85{
86    return mElement.isRogue();
87}
88
89bool ElementHandle::isArray() const
90{
91    return getArrayLength() != 0;
92}
93
94size_t ElementHandle::getArrayLength() const
95{
96    // Only instances can be arrays, SystemClass can not, nor subsystems
97    auto *instance = dynamic_cast<CInstanceConfigurableElement *>(&mElement);
98    if (instance == nullptr) {
99        return 0;
100    }
101    return instance->getArrayLength();
102}
103
104string ElementHandle::getPath() const
105{
106    return mElement.getPath();
107}
108
109string ElementHandle::getKind() const
110{
111    return mElement.getKind();
112}
113
114std::vector<ElementHandle> ElementHandle::getChildren()
115{
116    size_t nbChildren = mElement.getNbChildren();
117
118    std::vector<ElementHandle> children;
119    children.reserve(nbChildren);
120
121    for (size_t childIndex = 0; childIndex < nbChildren; ++childIndex) {
122        auto *child = static_cast<CConfigurableElement *>(mElement.getChild(childIndex));
123        // Can not use emplace back as the constructor is private
124        children.push_back({*child, mParameterMgr});
125    }
126    return children;
127}
128
129bool ElementHandle::getMappingData(const string &strKey, string &strValue) const
130{
131    const std::string *pStrValue;
132
133    // Seach for the key in self and ancestors
134    auto elements = mElement.getConfigurableElementContext();
135
136    for (auto *element : elements)
137        if (element->getMappingData(strKey, pStrValue)) {
138            strValue = *pStrValue;
139            return true;
140        }
141
142    return false;
143}
144
145bool ElementHandle::getStructureAsXML(std::string &xmlSettings, std::string &error) const
146{
147    // Use default access context for structure export
148    CParameterAccessContext accessContext(error);
149    return mParameterMgr.exportElementToXMLString(
150        &mElement, mElement.getXmlElementName(),
151        CXmlParameterSerializingContext{accessContext, error}, xmlSettings);
152}
153
154template <class T>
155struct isVector : std::false_type
156{
157};
158template <class T>
159struct isVector<std::vector<T>> : std::true_type
160{
161};
162
163bool ElementHandle::getAsXML(std::string &xmlValue, std::string &error) const
164{
165    std::string result;
166    if (not mParameterMgr.getSettingsAsXML(&mElement, result)) {
167        error = result;
168        return false;
169    }
170
171    xmlValue = result;
172    return true;
173}
174
175bool ElementHandle::setAsXML(const std::string &xmlValue, std::string &error)
176{
177    return mParameterMgr.setSettingsAsXML(&mElement, xmlValue, error);
178}
179
180bool ElementHandle::getAsBytes(std::vector<uint8_t> &bytesValue, std::string & /*error*/) const
181{
182    mParameterMgr.getSettingsAsBytes(mElement, bytesValue);
183
184    // Currently this operation can not fail.
185    // Nevertheless this is more a design than intrinsic property.
186    // Use the same error reporting pattern to avoid breaking the api in future
187    // release if an error need to be reported (and be consistent with all other getAs*).
188    return true;
189}
190
191bool ElementHandle::setAsBytes(const std::vector<uint8_t> &bytesValue, std::string &error)
192{
193    return mParameterMgr.setSettingsAsBytes(mElement, bytesValue, error);
194}
195
196template <class T>
197bool ElementHandle::setAs(const T value, string &error) const
198{
199    if (not checkSetValidity(getUserInputSize(value), error)) {
200        return false;
201    }
202    // Safe downcast thanks to isParameter check in checkSetValidity
203    auto &parameter = static_cast<CBaseParameter &>(mElement);
204
205    // When in tuning mode, silently skip "set" requests
206    if (mParameterMgr.tuningModeOn()) {
207
208        return true;
209    }
210
211    CParameterAccessContext parameterAccessContext(error, mParameterMgr.getParameterBlackboard());
212
213    // BaseParamere::access takes a non-const argument - therefore we need to
214    // copy the value
215    T copy = value;
216
217    // Ensure we're safe against blackboard foreign access
218    lock_guard<mutex> autoLock(mParameterMgr.getBlackboardMutex());
219
220    return parameter.access(copy, true, parameterAccessContext);
221}
222
223template <class T>
224bool ElementHandle::getAs(T &value, string &error) const
225{
226    if (not checkGetValidity(isVector<T>::value, error)) {
227        return false;
228    }
229    // Safe downcast thanks to isParameter check in checkGetValidity
230    auto &parameter = static_cast<const CBaseParameter &>(mElement);
231
232    // Ensure we're safe against blackboard foreign access
233    lock_guard<mutex> autoLock(mParameterMgr.getBlackboardMutex());
234
235    CParameterAccessContext parameterAccessContext(error, mParameterMgr.getParameterBlackboard());
236
237    return parameter.access(value, false, parameterAccessContext);
238}
239
240// Boolean access
241bool ElementHandle::setAsBoolean(bool value, string &error)
242{
243    return setAs(value, error);
244}
245
246bool ElementHandle::getAsBoolean(bool &value, string &error) const
247{
248    return getAs(value, error);
249}
250
251bool ElementHandle::setAsBooleanArray(const std::vector<bool> &value, string &error)
252{
253    return setAs(value, error);
254}
255
256bool ElementHandle::getAsBooleanArray(std::vector<bool> &value, string &error) const
257{
258    return getAs(value, error);
259}
260
261// Integer Access
262bool ElementHandle::setAsInteger(uint32_t value, string &error)
263{
264    return setAs(value, error);
265}
266
267bool ElementHandle::getAsInteger(uint32_t &value, string &error) const
268{
269    return getAs(value, error);
270}
271
272bool ElementHandle::setAsIntegerArray(const std::vector<uint32_t> &value, string &error)
273{
274    return setAs(value, error);
275}
276
277bool ElementHandle::getAsIntegerArray(std::vector<uint32_t> &value, string &error) const
278{
279    return getAs(value, error);
280}
281
282// Signed Integer Access
283bool ElementHandle::setAsSignedInteger(int32_t value, string &error)
284{
285    return setAs(value, error);
286}
287
288bool ElementHandle::getAsSignedInteger(int32_t &value, string &error) const
289{
290    return getAs(value, error);
291}
292
293bool ElementHandle::setAsSignedIntegerArray(const std::vector<int32_t> &value, string &error)
294{
295    return setAs(value, error);
296}
297
298bool ElementHandle::getAsSignedIntegerArray(std::vector<int32_t> &value, string &error) const
299{
300    return getAs(value, error);
301}
302
303// Double Access
304bool ElementHandle::setAsDouble(double value, string &error)
305{
306    return setAs(value, error);
307}
308
309bool ElementHandle::getAsDouble(double &value, string &error) const
310{
311    return getAs(value, error);
312}
313
314bool ElementHandle::setAsDoubleArray(const std::vector<double> &value, string &error)
315{
316    return setAs(value, error);
317}
318
319bool ElementHandle::getAsDoubleArray(std::vector<double> &value, string &error) const
320{
321    return getAs(value, error);
322}
323
324// String Access
325bool ElementHandle::setAsString(const string &value, string &error)
326{
327    return setAs(value, error);
328}
329
330bool ElementHandle::getAsString(string &value, string &error) const
331{
332    return getAs(value, error);
333}
334
335bool ElementHandle::setAsStringArray(const std::vector<string> &value, string &error)
336{
337    return setAs(value, error);
338}
339
340bool ElementHandle::getAsStringArray(std::vector<string> &value, string &error) const
341{
342    return getAs(value, error);
343}
344
345bool ElementHandle::checkGetValidity(bool asArray, string &error) const
346{
347    if (not isParameter()) {
348        error = "Can not set element " + getPath() + " as it is not a parameter.";
349        return false;
350    }
351
352    if (asArray != isArray()) {
353
354        auto toStr = [](bool array) { return array ? "an array" : "a scalar"; };
355        error = "Can not get \"" + getPath() + "\" as " + toStr(asArray) + " because it is " +
356                toStr(isArray());
357        return false;
358    }
359
360    return true;
361}
362
363// Access validity
364bool ElementHandle::checkSetValidity(size_t arrayLength, string &error) const
365{
366    // Settings a parameter necessitates the right to get it
367    if (not checkGetValidity(arrayLength != 0, error)) {
368        return false;
369    }
370
371    if (!isRogue()) {
372
373        error = "Can not set parameter \"" + getPath() + "\" as it is not rogue.";
374        return false;
375    }
376
377    if (arrayLength && (arrayLength != getArrayLength())) {
378
379        using std::to_string;
380        error = "Array length mismatch for \"" + getPath() + "\", expected: " +
381                to_string(getArrayLength()) + ", got: " + to_string(arrayLength);
382        return false;
383    }
384
385    return true;
386}
387