Return to ObjectBuilder.cpp CVS log | Up to [Pegasus] / pegasus / src / Clients / cimcli |
File: [Pegasus] / pegasus / src / Clients / cimcli / ObjectBuilder.cpp
(download)
Revision: 1.19, Mon Feb 18 15:00:20 2013 UTC (11 years, 4 months ago) by marek Branch: MAIN CVS Tags: TASK-TASK_PEP362_RestfulService_branch-root, TASK-TASK_PEP362_RestfulService_branch-merged_out_from_trunk, TASK-TASK_PEP362_RestfulService_branch-merged_in_to_trunk, TASK-TASK_PEP362_RestfulService_branch-merged_in_from_branch, TASK-TASK_PEP362_RestfulService_branch-branch, TASK-PEP362_RestfulService-root, TASK-PEP362_RestfulService-merged_in_to_trunk, TASK-PEP362_RestfulService-merged_in_from_branch, RELEASE_2_13_0-RC2, RELEASE_2_13_0-RC1, RELEASE_2_13_0-FC, RELEASE_2_13_0, RELEASE_2_13-root, RELEASE_2_13-branch, CIMRS_WORK_20130824 Branch point for: TASK-PEP362_RestfulService-branch Changes since 1.18: +0 -5 lines BUG#:9536 TITLE: tweak PEGASUS_ASSERT and other macro to avoid unused warnings and build break DESCRIPTION: |
//%LICENSE//////////////////////////////////////////////////////////////// // // Licensed to The Open Group (TOG) under one or more contributor license // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with // this work for additional information regarding copyright ownership. // Each contributor licenses this file to you under the OpenPegasus Open // Source License; you may not use this file except in compliance with the // License. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ////////////////////////////////////////////////////////////////////////// // //%///////////////////////////////////////////////////////////////////////////// #include <Pegasus/Common/Config.h> #include <Pegasus/Common/Constants.h> #include <Pegasus/Common/PegasusAssert.h> #include <Pegasus/Common/StringConversion.h> #include <Pegasus/Common/Tracer.h> #include <Pegasus/Common/XmlWriter.h> #include "CIMCLIClient.h" #include "ObjectBuilder.h" #include "CIMCLICommon.h" #include <Pegasus/Common/ArrayInternal.h> #include <Pegasus/Common/ArrayIterator.h> #include <Clients/cliutils/CsvStringParse.h> PEGASUS_USING_STD; PEGASUS_NAMESPACE_BEGIN // Define a Pegasus array implementation for the tokenItem type #define PEGASUS_ARRAY_T tokenItem # include <Pegasus/Common/ArrayImpl.h> #undef PEGASUS_ARRAY_T // Diagnostic dislays activated if verboseTest set to true below. This is // compile time used for developer tests only. Tjis should be disabled // before code is released or automated tests run. bool verboseTest = false; #define VCOUT if (verboseTest) cout << "LINE=" << __LINE__ << " TST " // Cleans an input array by removing the { } tokens that surround // the array parameters. Does nothing if they do not exist. If there is // an unmatched set, an error is generated. // Allows the user to input array definitions surrounded by { } // as an option. void _cleanArray(String& x) { if (x[0] == '{' && x[x.size()] == '}') { x.remove(0,1); x.remove(x.size(),1); } else if (x[0] == '{' || x[x.size()] == '}') { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Unmatched { } in array $0", x); } } // FUTURE - Expand this for other date time literals suchs as TODAY // CIMDateTime _getDateTime(const String& str) { if (String::equalNoCase(str,"NOW")) { return CIMDateTime::getCurrentDateTime(); } return CIMDateTime(str); } Boolean _StringToBoolean(const String& x) { if (String::equalNoCase(x,"true")) { return true; } else if (String::equalNoCase(x,"false")) { return false; } // NOTE: please code with both the error code and the MessageLoaderParms // on the same line. Allows us to grep for messages that have been // internationalized easily. Thanks. KS cimcliMsg::exit(CIMCLI_INPUT_ERR, MessageLoaderParms( "Clients.cimcli.CIMCLIClient.BOOLEAN_VALUE_ERR", "Invalid keyword for boolean value = $0. " "Must be \"true\" or \"false\" upper or lower case",x)); return false; } Uint32 _includesType(const String& name) { // FUTURE KS add code. For now this is null because we do not // support the data type option on input. return 0; } /****************************************************************************** ** ** Implementation of tokenItem ** ******************************************************************************/ // return String for the tokenType. This is a diagnostic tool only. String tokenTypeToString(TokenType tokenType) { static const char * tokenTypeString[] = { "UNKNOWN","ILLEGAL", "VALUE", "NO_VALUE", "EXCLAM", "NAME_ONLY", "EMBED", "END_EMBED", "EMBED_NEXT_ARRAY_ITEM" }; return tokenTypeString[tokenType]; } tokenItem::tokenItem (const String& inputParam, String& name, String& value, TokenType& type) : tokenInput(inputParam),tokenValue(value), tokenType(type), duplicate(false) { if (name.size() != 0) { tokenName = CIMName(name); } } void tokenItem::print() { cout << toString() << endl; } // Convert info in single token to string for display. Diagnostic // tool String tokenItem::toString() { char tmp[22]; Uint32 cvtSize; String x = "TOKEN: Name="; x.append(tokenName.getString()); x.append(", value="); x.append(tokenValue); x.append(", type="); x.append(tokenTypeToString(tokenType)); x.append(", input="); x.append(tokenInput); x.append(", duplicate="); x.append(_toString(duplicate)); x.append(" Instance count="); x.append(Uint32ToString(tmp, _instances.size(), cvtSize)); for (Uint32 i = 0 ; i < _instances.size(); i++) { x.append(Uint32ToString(tmp, i, cvtSize)); x.append("\n Instance # "); x.append(Uint32ToString(tmp, i, cvtSize)); x.append(_instances[i].isUninitialized()? " EMPTY" : " EXISTS"); if (!_instances[i].isUninitialized()) { XmlWriter::printInstanceElement(_instances[i], cout); } } x.append(" \n}\n"); return x; } /***************************************************************************** ** ** local support functions for Object Builder ** ******************************************************************************/ /** Parse the input string to separate out the name and value components. The name component must be a CIM_Name and contain only alphanumerics and _ characters. The value is optional. The possible separators are today "=", "{" and "!". and no value component is allowed after the ! separator Includes the possibility of Embedded Instances where the property name is terminated by { and the following pairs are 1. classname, propertyname/value pairs * @param input String containing the input parameter @param name String name parsed from input parameter @param value String representing value component parsed from parameter @return TokenType Token type that resulted from this parse */ tokenItem parseInputParam(const String& input) { TokenType tokenType = UNKNOWN; String value; String name; // Scan the input string for a terminator character. Uint32 index = 0; for ( ; index < input.size() ; index++) { switch(input[index]) { case '=': if (index < input.size()) { if (input[index+1] == '{') { tokenType = EMBED; index++; } else tokenType = VALUE; } else tokenType = VALUE; break; case '!': tokenType = EXCLAM; break; case '{': tokenType = EMBED; break; case '}': if (input.subString(index,3) == "}.{") { tokenType = EMBED_NEXT_ARRAY_ITEM; index +=2; } else { tokenType = END_EMBED; } break; default: name.append(input[index]); } // end case statement // break the loop if separator found if (tokenType != UNKNOWN) { break; } } // separator must be found if (tokenType == UNKNOWN) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "No name/value separator in $0." "Parameters must have separator such as " "= { ={ } !", input); } // There must be a name entity except for END_EMBED else if (name.size() == 0 && tokenType != END_EMBED && tokenType != EMBED_NEXT_ARRAY_ITEM) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "No name on input parameter $0 ",input); } // get the value component from the remaining characters of input else { value = input.subString(index + 1, PEG_NOT_FOUND); if (value.size() == 0) { if (tokenType == VALUE) { tokenType = NO_VALUE; } } } // disgnostic output when verbose set. VCOUT << "Input Parse of " << input << " into tokenType=" << tokenTypeToString(tokenType) << " name=" << name << " value=" << value << endl; tokenItem ti(input, name, value, tokenType); return ti; } /* Convert a single string provided as input into a new CIM variable and place it in a CIMValue. This function does not process Embedded instances/objects since they are not represented as a single string. @param str char* representing string to be parsed. @param type CIMType expected. @return CIMValue with the new value. If the parse fails, this function terminates with an exit CIMCLI_INPUT_ERR. */ static CIMValue _stringToScalarValue(const char* str, CIMType type) { switch (type) { case CIMTYPE_BOOLEAN: return CIMValue(_StringToBoolean(str)); case CIMTYPE_UINT8: return CIMValue(Uint8(strToUint(str, type))); case CIMTYPE_SINT8: return CIMValue(Sint8(strToSint(str, type))); case CIMTYPE_UINT16: return CIMValue(Uint16(strToUint(str, type))); case CIMTYPE_SINT16: return CIMValue(Sint16(strToSint(str, type))); case CIMTYPE_UINT32: return CIMValue(Uint32(strToUint(str, type))); case CIMTYPE_SINT32: return CIMValue(Sint32(strToSint(str, type))); case CIMTYPE_UINT64: return CIMValue(Uint64(strToUint(str, type))); case CIMTYPE_SINT64: return CIMValue(Sint64(strToSint(str, type))); case CIMTYPE_REAL32: return CIMValue(Real32(strToReal(str, type))); case CIMTYPE_REAL64: return CIMValue(Real64(strToReal(str, type))); case CIMTYPE_STRING: return CIMValue(String(str)); case CIMTYPE_DATETIME: return CIMValue(_getDateTime(str)); case CIMTYPE_REFERENCE: return CIMValue(CIMObjectPath(str)); default: cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Data type $0 build from string not allowed", cimTypeToString(type)); } return CIMValue(); } /* Parse out comma-separated values from input string and build the CIMValue array representing the input for array type input entities. @param str const char * containing the comma-separated values to be parsed. All value elements in the CSV string must be parsable to the same type. This function does not handle the CIMInstance or CIMObject types since they are not a single string on input. @param v CIMValue into which the resulting values are appended to any existing values. This allows building array CIMValues from repeated input of single property definitions rather than having to input the entire array at one time. @return Returns complete CIMValue. */ Boolean _stringToArrayValue( const char * str, CIMValue& val) { CIMType type = val.getType(); String parseStr(str); csvStringParse strl(parseStr, ','); switch (type) { case CIMTYPE_BOOLEAN: { Array<Boolean> a; val.get(a); while(strl.more()) { a.append(_StringToBoolean(strl.next())); } val.set(a); break; } case CIMTYPE_UINT8: { Array<Uint8> a; val.get(a); while(strl.more()) { a.append(strToUint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_SINT8: { Array<Sint8> a; val.get(a); while(strl.more()) { a.append(strToSint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_UINT16: { Array<Uint16> a; val.get(a); while(strl.more()) { a.append(strToUint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_SINT16: { Array<Sint16> a; val.get(a); while(strl.more()) { a.append(strToSint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_UINT32: { Array<Uint32> a; val.get(a); while(strl.more()) { a.append(strToUint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_SINT32: { Array<Sint32> a; val.get(a); while(strl.more()) { a.append(strToSint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_UINT64: { Array<Uint64> a; val.get(a); while(strl.more()) { a.append(strToUint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_SINT64: { Array<Sint64> a; val.get(a); while(strl.more()) { a.append(strToSint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_REAL32: { Array<Real32> a; val.get(a); while(strl.more()) { a.append(strToSint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_REAL64: { Array<Real64> a; val.get(a); while(strl.more()) { a.append(strToSint(strl.next().getCString(), type)); } val.set(a); break; } case CIMTYPE_STRING: { Array<String> a; val.get(a); while(strl.more()) { a.append(strl.next()); } val.set(a); break; } case CIMTYPE_DATETIME: { Array<CIMDateTime> a; val.get(a); while(strl.more()) { a.append(_getDateTime(strl.next())); } val.set(a); break; } case CIMTYPE_REFERENCE: { Array<CIMObjectPath> a; val.get(a); while(strl.more()) { a.append(CIMObjectPath(strl.next())); } val.set(a); break; } default: cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Data type $0 build from string not allowed", cimTypeToString(type)); } return true; } // Complete the defined value item (iv) by modifying or setting the value. // The input is expected to have the correct CIMType and array information // Common builder for parameters and properties. This handles all // CIM data types but uses the _stringTo.. functions for all but the // CIMInstance and CIMObject types void _buildValueFromToken(tokenItem& token, CIMValue& iv, CIMType cimType) { VCOUT <<"_buildValueFromToken cimType=" << cimTypeToString(cimType) << " token=" << token.toString() << endl; if (!iv.isArray()) { // FUTURE: Should this be an error or warning? The question exists // because we consider unknown property names as warnings. if (token.duplicate) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Duplicate scalar property Name. $0", token.tokenInput); } } switch (token.tokenType) { case EXCLAM: { if (cimType == CIMTYPE_STRING) { // Set property to empty string iv.set(String()); } else { cimcliMsg::exit(CIMCLI_INPUT_ERR, "\"!\" terminator allowed only on String type. " " Parameter= $0",token.tokenInput); } break; } case VALUE: { if (iv.isArray()) { _cleanArray(token.tokenValue); // Append array to existing value if (!_stringToArrayValue(token.tokenValue.getCString(), iv)) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Error parsing Array parameter. $0", token.tokenInput); } } else // scalar { // Replace property value in property. iv = _stringToScalarValue(token.tokenValue.getCString(), cimType); } break; } // Embedded token. should contain embedded instance built earlier // This will create either an embedded instance/object in CIMType // CIMInstance or CIMObject or a reference in a REF CIMType property case EMBED: { // Array of Instances should be in place here to put into property. if (token._instances.size() != 0) { // If array type, append to current property value if (iv.isArray()) { if (iv.getType() == CIMTYPE_INSTANCE) { Array<CIMInstance> insts; iv.get(insts); insts.append(token._instances[0]); iv.set(insts); } else if (iv.getType() == CIMTYPE_OBJECT) { Array<CIMObject> objects; iv.get(objects); objects.append((CIMObject)token._instances[0]); iv.set(objects); } else if (iv.getType() == CIMTYPE_REFERENCE) { // augment the array of paths and set into the value Array<CIMObjectPath> paths; iv.get(paths); CIMObjectPath thisPath = token._instances[0].buildPath(token._class); paths.append(thisPath); iv.set(paths); } else { cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Invalid CIM datatype on embedded object. " "CIMType=Token=$0" " token = $1", cimTypeToString(iv.getType()), token.toString()); } } else // Scalar. set token to property value { // Since this is a scalar, there should only be a // single instance. if (token._instances.size() > 1 ) { cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Multiple instances generated for " "scalar property $0 at input parameter $1", token.tokenName.getString(), token.tokenInput); } CIMInstance inst = token._instances[0]; VCOUT << "buildInstance EMBED Instance found" << " classname=" << inst.getClassName().getString() << " iv type=" << cimTypeToString(cimType) << endl; // set the new instance into the value if (cimType == CIMTYPE_INSTANCE) { iv.set(inst); } else if (cimType == CIMTYPE_OBJECT) { iv.set((CIMObject)inst); } else if (iv.getType() == CIMTYPE_REFERENCE) { // Build the path from the instance in the token // and class in the token. CIMObjectPath thisPath = inst.buildPath(token._class); iv.set(thisPath); } else { cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Invalid CIM datatype on embedded object. " "CIMType=$0" " Token=$1", cimTypeToString(iv.getType()), token.toString()); } } } else // Must be instances available if parse worked { cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Embedded Instance(s) not built. Token=$0", token.toString()); } break; } // In case of no value, just pass value existing in input CIMValue case NO_VALUE: { break; } default: { cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Invalid token on building CIMValue. Token=$0", token.toString()); } } } /* Build the CIMValue for a single property from the input itemToken and set it into the input property. Errors generate exit. @param token itemToken defines value, type, etc. for this property @param ip CIMProperty in instance being built. New value from token replaces existing value in property. */ void _buildPropertyValue(tokenItem& token, CIMProperty& ip) { CIMType cimType = ip.getType(); CIMValue iv = ip.getValue(); _buildValueFromToken(token, iv, cimType); // Set new value back into property. ip.setValue(iv); } /* Create a method parameter from the tokenized information for the method name, value, type, etc. */ CIMParamValue _buildMethodParamValue( tokenItem ti, const CIMParameter& thisParameter, CIMValue& curValue, Boolean verbose) { VCOUT << "_createMethodParamValue " << " tokenItem= " << ti.toString() << " Param type=" << cimTypeToString(thisParameter.getType()) << " Param isArray=" << (thisParameter.isArray()? "true" : "false") << " curValue type= " << cimTypeToString(curValue.getType()) << " paramName=" << thisParameter.getName().getString() << endl; CIMType cimType = curValue.getType(); String paramName = thisParameter.getName().getString(); CIMValue vp = curValue; _buildValueFromToken(ti, vp, cimType); // build the Parameter Value with isTyped == true return CIMParamValue(paramName,vp,true); } /**************************************************************************** Defines an iterator class for String arrays. This class is used to make the input parameter list parsing more understandable than a for loop. ****************************************************************************/ class iterateArray { public: // construct an iterator for an array iterateArray(Array<String> input) : _array(input), _pos(0), _prev(String()) { } // Create new iterator starting from nonzero position // in input array iterateArray(Array<String> input, Uint32 pos) : _array(input), _pos(pos), _prev(String()) { } // return true if more available Boolean more() { return (_pos < _array.size()? true : false); } // mget next item. This is item currently pointed // to. And advance pointer to next item. next MUST // BE proceeded by more() since there is no check here String next() { if (!more()) { cerr << "Internal Error in iterateArray" << endl; cimcliExit(CIMCLI_INTERNAL_ERR); } _prev = _array[_pos]; VCOUT << "next returns " << _prev << " at pos " << _pos << endl; return _array[_pos++]; } // get previous entry String prev() { if (_pos == 0) { cerr << "Internal Error in iterateArray" << endl; cimcliExit(CIMCLI_INTERNAL_ERR); } return _prev; } // get position Uint32 pos() { return _pos; } // insert x at current position in the array void insert(String x) { _array.insert(_pos, x); } void printList() { VCOUT << "Input is " << _array.size() << " value parameters" << endl; for (Uint32 i = 0 ; i < _array.size() ; i++) { VCOUT << i << " value " << _array[i] << endl; } } private: Array<String> _array; Uint32 _pos; String _prev; }; /****************************************************************** * * ObjectBuilder Class. Creates instances and parameters from * name/value pairs received and the corresponding class * definitions. * *******************************************************************/ // Common Scan loop to Scan input Value Parameter list. This loop is used // both by the outer constructor (recurselevel == 0) to control scan of // all value parameters and by the embedded Object constructor which // scans a part of the value parameter list for a single embedded object void ObjectBuilder::scanInputList(CIMClient& client, const CIMNamespaceName& nameSpace, const CIMPropertyList& cimPropertyList, iterateArray& ia, Uint32& recurseLevel, const CIMName& featureName) { // Set true when end of embedded object "}" or "}.{" found in // the scan for a single embedded object. Boolean embEndTokenFound = false; while (ia.more()) { // parse each input parameter and eliminate any illegal returns // Each successful creates new tokenItem tokenItem ti = parseInputParam(ia.next()); // process based on the returned tokenItem type. switch(ti.tokenType) { case EMBED: { // If embedded indicator, get next token as embedded // classname unless value returned if (ti.tokenValue.size() == 0) { // get class name. If no inputParamList, error if (!ia.more()) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "No embedded instance classname at ", ti.tokenInput); } else { // Set next input param to Class to use ti.tokenValue = ia.next(); } } // Parse and buildInstance for the embedded object. // Returns built instance and inputParamList pos at next // input parameter after end marker of this embedded // instance ObjectBuilder obj(ia, client, nameSpace, ti, cimPropertyList, _verbose, _instance, ++recurseLevel); // Review this for alternate place to do the // append. Since ti is part of the recursive call, why not // do the insert there instead of returning the objects // to this level. // Append new instance into any existing array of instances // for this token and append the token to the token list ti._instances.append(_instance); appendToken(ti); break; } case EMBED_NEXT_ARRAY_ITEM: case END_EMBED: { // Should not find end markers at the zero recurse level if (recurseLevel == 0) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Unmatched Embedded instance" " end marker(s) at parameter=\"$0\"", ti.tokenInput); } else { // END_EMBED found, build instance // with current tokens to be returned. Return it in // CIMInstance parameter. includeQualifiers and // includeClassOrigin are false. // buildInstance(...) insures that an instance is built // If this is the NEXT_ARRAY marker "},{" continue scan // by reinserting <featureName>{<classname> into the // input parameter list which fully defines the next item // as an array item of the same featureName. if (ti.tokenType == EMBED_NEXT_ARRAY_ITEM) { String x = featureName.getString(); x.append("{"); x.append(_className.getString()); ia.insert(x); // Diagnostic ia.printList(); } // set flag to stop since end embed tag found embEndTokenFound = true; } break; } // This may be completely redundant and maybe we // should solve in the param parser case ILLEGAL: { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Parse Failed. Input Parameter=\"$0\" $1", ti.tokenInput, ((ti.tokenName.getString().size() == 0)? "No Name Component" : "") ); } default: { appendToken(ti); } } // end case // exit the input processing loop early if flag set. if (embEndTokenFound) { break; } } // end while(ia.more()) // If we do not find an end_embed marker ( "}" ) report error and in // inner constructor, error if (!embEndTokenFound && (recurseLevel != 0)) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Missing Embedded object Terminator i.e. \"}\""); } // If verbose flag set, display all tokens created in this object // builder object. if (_verbose) { // Display all the names and // property values of the instance with their token type // FUTURE Clean up this display to be more readable since in // involves an internal structure that we display. cout << "Display all tokens created for input parameter analysis" << endl; printTokens(); } } /* Constructor, sets up a single object with the input parameter list and the definition to get the class required for the parsing and entity building. A parameter on this list is the definition of one input parameter representing the definition of a property or parameter. It is in the form of a name/value pair with a token separating the name and value that definesthe action to be taken with this pair. The possible actions are defined by the TokenType enumerate including: - Use value string as input to define the value of a cim data type - Treat this as an empty string - no value - create a null value - Treat this as the start of an embedded object definition - Treat as end of an embedded object definition */ ObjectBuilder::ObjectBuilder( Array<String>& inputParamList, CIMClient& client, const CIMNamespaceName& nameSpace, const CIMName& className, const CIMPropertyList& cimPropertyList, Boolean verbose) : _className(className), _verbose(verbose) { // Get the class. Exceptions including class_not_found are automatic // not localOnly (Need all properties), get qualifiers and classOrigin // since we can filter them out later _thisClass = client.getClass(nameSpace, className, false,true,true,cimPropertyList); // Loop starts from 1, since the Class Name is first parameter // and we want only the property name and value here // Parse all of the name/value pairs from the input. iterateArray ia(inputParamList, 1); // Diagnostic to print input param list when verbose set. ia.printList(); Uint32 recurseLevel = 0; scanInputList(client, nameSpace, cimPropertyList, ia, recurseLevel, CIMName()); } ObjectBuilder::ObjectBuilder(iterateArray& ia, CIMClient& client, const CIMNamespaceName& nameSpace, tokenItem& tiInput, const CIMPropertyList& cimPropertyList, // used to getClass Boolean verbose, CIMInstance& rtnInstance, Uint32& recurseLevel) : _className(tiInput.tokenValue), _verbose(verbose) { VCOUT << "ObjectBuider Embedded Constructor level=" << recurseLevel << " class=" <<_className.getString() << " FeatureName=" << tiInput.tokenName.getString() << " pos=" << ia.pos() << endl; // Get the feature name from the token (features are properties or // methods) CIMName featureName = tiInput.tokenName; // get the class. Exceptions including class_not_found are automatic // not localOnly (Need all properties), get qualifiers and classOrigin // since we can filter them out later _thisClass = client.getClass(nameSpace, _className, false,true,true,cimPropertyList); tiInput._class = _thisClass; // Scan the input parameters to build a list of tokens representing // a single embedded definition ( between ={ and } scanInputList(client, nameSpace, cimPropertyList, ia, recurseLevel, featureName); // Build the resulting instance and return it as a parameter from the // token set createeated in the scan. Always build an instance since // that is used eve even to build reference properties. rtnInstance = buildInstance(false, false, CIMPropertyList()); recurseLevel--; } ObjectBuilder::~ObjectBuilder() { } void ObjectBuilder::printTokens(String message) { if (message.size() != 0) { VCOUT << message << endl; } VCOUT << _tokens.size() << " Tokens exist for class=" << _className.getString() << endl; if (verboseTest) { for (Uint32 i = 0; i < _tokens.size(); i++) { _tokens[i].print(); } } } Array<CIMName> ObjectBuilder::getPropertyList() { Array<CIMName> n; for (Uint32 i = 0; i < _tokens.size(); i++) { n.append(_tokens[i].tokenName); } return n; } const CIMClass ObjectBuilder::getTargetClass() { return _thisClass; } CIMObjectPath ObjectBuilder::buildCIMObjectPath() { CIMInstance testInstance = buildInstance( true, true, CIMPropertyList()); CIMObjectPath thisPath = testInstance.buildPath(_thisClass); return thisPath; } /* Build an instance from the information in the ObjectBuilder object. */ CIMInstance ObjectBuilder::buildInstance( Boolean includeQualifiers, Boolean includeClassOrigin, const CIMPropertyList& propertyList) { // Create the instance skeleton from class downloaded in ObjectBuilder // constructor with all properties CIMInstance newInstance = _thisClass.buildInstance( includeQualifiers, includeClassOrigin, CIMPropertyList()); if (newInstance.isUninitialized()) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Failed to build Instance for class $0", _thisClass.getClassName().getString()); } Array<CIMName> myPropertyList; Uint32 propertyPos; // Set all the input property values that have tokenItem definitions // into an instance of the defined class for (Uint32 index = 0; index < _tokens.size(); index++) { // test if property in class. Note that this is not a fatal error // today but just outputs a message. We just ignore that property // input value and continue to the next property. if ((propertyPos = _thisClass.findProperty( _tokens[index].tokenName)) == PEG_NOT_FOUND) { cerr << "Warning: property \"" << _tokens[index].tokenName.getString() << "\" not in class: " << _thisClass.getClassName().getString() << ". Skipping." << endl; continue; } // get value for this property from built instance CIMProperty ip = newInstance.getProperty(propertyPos); // If input not NULL type (ends with =) set the value component // into property. NULL input sets whatever is in the class into // the instance (done by buildInstance) _buildPropertyValue(_tokens[index], ip); // Append this property name to list of properties processed myPropertyList.append(CIMName(_tokens[index].tokenName)); } // Delete any properties not on the list of properties processed. newInstance.instanceFilter(includeQualifiers, includeClassOrigin, myPropertyList); // Display the Instance if verbose if (_verbose) { cout << "Instance Built" << endl; XmlWriter::printInstanceElement(newInstance, cout); } return newInstance; } // test if an array of CIMParamValue contains a parameter with the // defined name. Uint32 _find(const Array<CIMParamValue>& params, const CIMName& name) { for(Uint32 i = 0 ; i < params.size(); i++) { if (params[i].getParameterName() == name) { return i; } } return PEG_NOT_FOUND; } Array<CIMParamValue> ObjectBuilder::buildMethodParameters(CIMName& name) { Array<CIMParamValue> params; // Find Method Uint32 methodPos; CIMMethod thisClassMethod; // test for method in class if ((methodPos = _thisClass.findMethod(name)) == PEG_NOT_FOUND) { // Allow execution even if method name not found but bypass // parameter analysis. cerr << "Warning: method " << name.getString() << " Not method in the class " << _className.getString() << endl; return params; } else { thisClassMethod = _thisClass.getMethod(methodPos); } // Build parameter for each token defined for (Uint32 index = 0; index < _tokens.size(); index++) { Uint32 parameterPos; // Warning if parameter not defined in class. The problem is that we // do not know what typing to apply so define as string with // any value supplied. if ((parameterPos = thisClassMethod.findParameter( CIMName(_tokens[index].tokenName))) == PEG_NOT_FOUND) { cimcliMsg::msg("Warning: " "Parameter $0 not valid method parameter in class $1", _tokens[index].tokenName.getString(), _className.getString()); CIMValue v(_tokens[index].tokenValue); CIMParamValue rtnParamValue( _tokens[index].tokenName.getString(), v); params.append(rtnParamValue); continue; } CIMParameter thisParameter = thisClassMethod.getParameter(parameterPos); // Initialize CIMValue for this parameter // Determine if this is embedded type from class qualifiers. // If so, modify type to the correct embedded type. CIMType cimType = thisParameter.getType(); for (Uint32 i = 0; i < thisParameter.getQualifierCount() ; i++) { CIMConstQualifier q = thisParameter.getQualifier(i); if (q.getName() == "EmbeddedInstance") { cimType = CIMTYPE_INSTANCE; } else if(q.getName() == "EmbeddedObject") { cimType = CIMTYPE_OBJECT; } } CIMValue curValue(cimType, thisParameter.isArray()); // Already processed this parameter name? Allowed if this // is an array since we may build arrays of values by repeating the // parameter input with (ex. to build arrays of instances). Uint32 pos; if((pos = _find(params, thisParameter.getName())) != PEG_NOT_FOUND) { // if Array type, we will want to append to value. Get the // current value from the /params array if it already exists. // remove existing parameter and replace it. if (thisParameter.isArray()) { CIMValue v = params[pos].getValue(); curValue = v; params.remove(pos); } else // If scalar, multiples are illegal. { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Multiple definition of scalar parameter name=$0", thisParameter.getName().getString()); } } // Build a ParamValue from the token, Class Parameter and // current CIMValue elements if (verboseTest) {_tokens[index].print();} CIMParamValue rtnParamValue = _buildMethodParamValue( _tokens[index], thisParameter, curValue, _verbose); // failed to build the parameter. Fatal error if (rtnParamValue.isUninitialized()) { cimcliMsg::exit(CIMCLI_INTERNAL_ERR, "Parse Error adding parameter $0", _tokens[index].tokenInput); } // Append parameter to return list. params.append(rtnParamValue); } return params; } // NOTE: Used by setProperty only. Need to modify whole setProperty logic // to scan input list, etc. before we modify this. // Current limitation is that setProperty does NOT handle embedded instances // or embedded Objects. CIMValue ObjectBuilder::buildPropertyValue( const CIMName& name, const String& value) { // Find Property Uint32 propertyPos; CIMProperty thisClassProperty; if ((propertyPos = _thisClass.findProperty(name)) == PEG_NOT_FOUND) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Property $0 not property in class $1", name.getString(), _className.getString()); } else { thisClassProperty = _thisClass.getProperty(propertyPos); } CIMType type = thisClassProperty.getType(); CIMValue vp(type,thisClassProperty.isArray()); if ((type == CIMTYPE_INSTANCE) || (type == CIMTYPE_OBJECT)) { cimcliMsg::exit(CIMCLI_INPUT_ERR, "Input of Instance or object types not allowed"); } if (vp.isArray()) { _stringToArrayValue(value.getCString(), vp ); return vp; } else { // scalar return _stringToScalarValue(value.getCString(), vp.getType()); } } void ObjectBuilder::appendToken(tokenItem ti) { for (Uint32 i = 0; i <_tokens.size() ; i++) { { if (_tokens[i].tokenName == ti.tokenName) { ti.duplicate = true; } } } _tokens.append(ti); } void ObjectBuilder::print() { cout << "ObjectBuilder instance\n" << "ClassName=" << _className.getString(); if (!_instance.isUninitialized()) { cout << "Instance exists" << endl; } else { cout << "No instance" << endl; } printTokens(); } PEGASUS_NAMESPACE_END // END_OF_FILE
No CVS admin address has been configured |
Powered by ViewCVS 0.9.2 |