go to post Daniel Kutac · Nov 28, 2018 For all non-Latin1 sites, this is highly individual and if performed on a long running systems that can not afford (long) interruption, a true challenge. One of our customers (hospital) has done this conversion earlier this year, it took several months to prepare everything, fine tune data migration (they used shadow mechanism to offload data to a Unicode server after initial conversion whilst running the two instances in parallel for testing and validation purposes). Once everything looked ok, and shadow server was in sync with data server, they switched to shadow (Unicode) machine.
go to post Daniel Kutac · Aug 30, 2018 Hi Dmitry,cool stuff indeed! (much cooler than one I made back in 2007 with plain CSP).Quick question: would it display contents of large databases (hundreds of GBs) in a readable way too?Dan
go to post Daniel Kutac · Aug 10, 2018 Hello Padma,sorry for delay in answering, I'm on vacation with limited access to computer. Glad you have resolved the issue!I was wondering what exactly are you trying to achieve, as grant type is determining messages flow between client and OAuth2 server. The way you authenticate yourself against Cache CSP (client) application is not related to the grant type at all. You can set your client CSP/ZEN app to use any Cache authentication. In one of project, where a Cache is issuing a HTTP request to a OAuth2 protected resource I'm using this code for password type grant:… main code try { set pResponse=##class(User.Response).%New() set tHttpRequest=##class(%Net.HttpRequest).%New() $$$THROWONERROR(tSC,..GetAccessToken()) $$$THROWONERROR(tSC,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,,tSSLConfig,..#oAUTH2aPPnAME,"NOTCSP")) // hardcoded sessionid to NOTCSP set tHttpRequest.Server=<server> set tHttpRequest.SSLCheckServerIdentity=0 set tURL=<whatever URL points to the resource> $$$THROWONERROR(tSC,tHttpRequest.Get(tURL)) #dim tHttpResponse as %Net.HttpResponse = tHttpRequest.HttpResponse $$$THROWONERROR(tSC,pResponse.Content.CopyFrom(tHttpResponse.Data)) } catch (e) { Set tSC=e.AsStatus() } and GetAccessToken method Method GetAccessToken() As %Status { #dim tSC as %Status = $$$OK try { //obtain Oauth2 token set tScope="user/*" set tApplication=..#oAUTH2aPPnAME set tSessionId="NOTCSP" set tUsername=<username> set tPassword=<password> #dim tError as %OAuth2.Error // verify we have already access token if '##class(%SYS.OAuth2.AccessToken).IsAuthorized(tApplication,tSessionId,tScope,.tAccessToken,.tIdToken,.tResponseProperties,.tError) { // we shall check whether we have access privileges, not done here //eventuallyt call ##class(%SYS.OAuth2.Validation).ValidateJWT() // retrieve token from auth server and store to internal peristent store $$$THROWONERROR(tSC,##class(%SYS.OAuth2.Authorization).GetAccessTokenPassword(tApplication,tUsername,tPassword,tScope,.tResponseProperties,.tError)) // load token to memory set tIsAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(tApplication,tSessionId,tScope,.tAccessToken,.tIdToken,.tResponseProperties,.tError) } if $isobject(tError) throw } catch (e) { throw e } Quit tSC }
go to post Daniel Kutac · Jul 13, 2018 This approach has an advantage over usign %GSIZE as the query in %SYS.GlobalQuery class has a parameter that can make quick estimations of the global sizes (simply counting # of blocks occupied by globals) rather than potentialy very slow exact global size determination always used by %GSIZE
go to post Daniel Kutac · Jul 3, 2018 Actually, advices given in other answer are quitec contradicting, one says install glassfish whilst other says uninstall glassfish.Why is Atelier at all trying to use glassfish?
go to post Daniel Kutac · Jul 3, 2018 Thank you Alexander,I tried to search community for this error but apparently I did not use correct keywords as I could not find previous posts with this very problem.At least we have a workaround as explained in links you provided.Dan
go to post Daniel Kutac · Jan 5, 2018 Evgeny,are there any plans to port it to Angular2+ ? e.g. connecting to ngx-charts?
go to post Daniel Kutac · Dec 27, 2017 Soufiane,supposing you have successfully been able to add the token to your client (this depends on ate respective framework) call for Cache resources (via REST API), then on Cache side, if that's where your data (resources) are sitting, you can use something like this:set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.tSC) // decode token data into JSON object $$$THROWONERROR(tSC,##class(%SYS.OAuth2.AccessToken).GetIntrospection($$$APP,accessToken,.jsonObjectAT)) /* service specific check */ // check whether the request is asking for proper scope for this service if '(jsonObjectAT.scope["special-deals") set reason=..#HTTP404NOTFOUND throw /* finally */ // validate signed access token (JWT) if '(##class(%SYS.OAuth2.Validation).ValidateJWT($$$APP,accessToken,,,.jsonObjectJWT,.securityParameters,.tSC)) { set reason=..#HTTP401UNAUTHORIZED $$$ThrowOnError(tSC) } perhaps you shall try to look at this post - https://community.intersystems.com/post/angular-client-demo-using-oauth2-authorization-server-protect-caché-based-resources, it also contains a link to the angular based project and contains implementation of sample Cache REST service. Dan
go to post Daniel Kutac · Dec 13, 2017 I think grant types are not used by he resource server, only by Confidential and Public clients.
go to post Daniel Kutac · Nov 14, 2017 Soufiane,briefly, perhaps not 100% correctly - use Google for more details, claims are characteristics provided by OIDC (OpenID Connect) server that describe authenticated user. e.g. Caché by default supports these claims (and more):preferred_username, email, email_verified, name, phone_number, phone_number_verified, iss, sub, aud, exp, auth_time, ...claims can be used by the access_token to provide additional information about the user passed to the resource server when calling REST method. Some claims are mandatory, some are optional. You can provide optional claims by the SetClaimValue() method.Dan
go to post Daniel Kutac · Oct 30, 2017 Evgeny, consider using OAuth2 with OpenID Connect as the first choice.Dan
go to post Daniel Kutac · Oct 12, 2017 Hi Praveen,this is not going to be an exhausting answer but rather a summary of choices you have.First thing to answer: are you working with a legacy application, that stored data in globals, not using our Cache persistent classes? In this case, you would like to follow Sean's globals to classes mapping guide.Another option, suitable in cases where you have a mix of persistent classes and only some data stored directly in globals, you may consider using custom SQL queries. In such query you implement code that iterates over your global nodes and expose result as SQL resultset. You can then call query as a standard stored procedure. see Cache online reference for mode details here.There is one more option too, which could be used in some special cases when global is a simple structure. In such case you could create a new persistent class definition and simply override the storage generated during its compilation to reflect your global structure. This is less flexible than using SQL mapping mentioned as first choice, but could be easier for you.HTH
go to post Daniel Kutac · Sep 20, 2017 there is an easy solution to your issue. Simply use a Cache Task Manager. Create a new task, and within code, instantiate Ensemble service Ens.Director,e.g. Set tSC=##class(Ens.Director).CreateBusinessService("your service configration name",.tService) If ($$$ISERR(tSC)) QuitSet tSC=tService.ProcessInput(%request,.output)If ($$$ISERR(tSC)) QuitIf $IsObject($G(output)) { // do whatever you want here}
go to post Daniel Kutac · Aug 3, 2017 Thanks Alexander,this seems promising. It works well for Year / MonthYear hierarchy, not working for Year/MonthNumber which I was using. My original hierarchy levels setup allowed me for easy year to year comparison of values for a given month.
go to post Daniel Kutac · Jul 18, 2017 Noone would give you exact numbers. It really depends on your use case.However, adding 200 properties to an Ensemble message (not considering other classes as you pass just messages) may either simp0ly mean that you add 200 properties to ONE class or to MANY classes, depending how clever the original design of your production was.You may, or with the same probability many not, need to change the message design and switch to virtual documents ... it really depends on many factors unique to your particular use case - throughput expected, load of data incoming etc etc...
go to post Daniel Kutac · Jul 18, 2017 Use your own custom Projection, put it into your primary class, it runs every time you compile your primary class, in the code you can do whatever you want, e.g. compile other classes.
go to post Daniel Kutac · Jul 14, 2017 Jose, $lb() holds STORED values of you object instance. If your opened instance modified property(ies) then I see no point of looking into stored data, just serialize you IN-MEMORY values to JSON.On the other hand, if a process A opened and modified instance of the object and without saving and you want to serialize the same instance from process B, then again, there is no difference between opening an object instance or using some custom serialization directly from stored data.It is not good practice anyway to keep objects opened for a long time without saving their new values.lastly, my comment about JSON array was that JSON array doesn't need to know the name in the name:value pair so you can easily write a custom JSON serializer to serialize directly $lb() into JSON array. maybe I missed your original business case need, can you explain why current implementation is not good enough for you?
go to post Daniel Kutac · Jul 14, 2017 Jose,how would you determine names of properties / keys for a JSON name:value pairs without opening an object instance or retrieving those names from somewhere else?or are you happy to express it as JSON ARRAY ?