Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
fabio martelli
syncope
Commits
28116e80
Unverified
Commit
28116e80
authored
Apr 21, 2017
by
Francesco Chicchiricco
Browse files
Bump upgrade to Syncope 2.0.3
parent
3510ce4d
Changes
97
Hide whitespace changes
Inline
Side-by-side
console/pom.xml
View file @
28116e80
...
...
@@ -6,7 +6,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
...
...
@@ -143,25 +143,43 @@ limitations under the License.
<phase>
process-resources
</phase>
<configuration>
<target>
<unzip
src=
"${settings.localRepository}/org/activiti/activiti-webapp-explorer2/${activiti.version}/activiti-webapp-explorer2-${activiti.version}.war"
dest=
"${project.build.directory}/activiti-webapp-explorer2"
/>
<unzip
src=
"${settings.localRepository}/org/activiti/activiti-webapp-explorer2/${activiti.version}/activiti-webapp-explorer2-${activiti.version}.war"
dest=
"${project.build.directory}/activiti-webapp-explorer2"
/>
<mkdir
dir=
"${activiti-modeler.directory}"
/>
<copy
file=
"${project.build.directory}/activiti-webapp-explorer2/modeler.html"
todir=
"${activiti-modeler.directory}"
/>
<replace
file=
"${activiti-modeler.directory}/modeler.html"
token=
"</head>"
value=
"<script type="text/javascript">window.onunload = refreshParent; function refreshParent() { window.opener.location.reload(); }</script></head>"
/>
<copy
file=
"${project.build.directory}/activiti-webapp-explorer2/WEB-INF/classes/stencilset.json"
todir=
"${activiti-modeler.directory}"
/>
<copy
file=
"${project.build.directory}/activiti-webapp-explorer2/modeler.html"
todir=
"${activiti-modeler.directory}"
/>
<replace
file=
"${activiti-modeler.directory}/modeler.html"
token=
"</head>"
value=
"<script type="text/javascript">window.onunload = refreshParent; function refreshParent() { window.opener.location.reload(); }</script></head>"
/>
<copy
file=
"${project.build.directory}/activiti-webapp-explorer2/WEB-INF/classes/stencilset.json"
todir=
"${activiti-modeler.directory}"
/>
<mkdir
dir=
"${activiti-modeler.directory}/editor-app"
/>
<copy
todir=
"${activiti-modeler.directory}/editor-app"
>
<fileset
dir=
"${project.build.directory}/activiti-webapp-explorer2/editor-app"
/>
</copy>
<replaceregexp
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
match=
"ORYX.CONFIG.ROOT_PATH =.*"editor/"; //TODO: Remove last slash!!"
replace=
"BASE_PATH = window.location.toString().substr(0, window.location.toString().indexOf('/wicket')); ORYX.CONFIG.ROOT_PATH = BASE_PATH + "/activiti-modeler/editor-app/editor/";"
byline=
"true"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
token=
"new Ajax.Request(ACTIVITI.CONFIG.contextRoot + '/editor/stencilset?version=' + Date.now(), {"
value=
"new Ajax.Request(window.location.toString().substr(0, window.location.toString().indexOf('/activiti-modeler')) + "/activiti-modeler/stencilset.json", {"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
token=
"ORYX.Editor.createByUrl(modelUrl);"
value=
"modelUrl = BASE_PATH + "/workflowDefGET"; ORYX.Editor.createByUrl(modelUrl);"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
token=
"ORYX.Editor.createByUrl = function(modelUrl){"
value=
"modelUrl = BASE_PATH + "/workflowDefGET"; ORYX.Editor.createByUrl = function(modelUrl){"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/configuration/toolbar-default-actions.js"
token=
"window.location.href = "./";"
value=
"window.close();"
/>
<replaceregexp
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
match=
"ORYX.CONFIG.ROOT_PATH =.*"editor/"; //TODO: Remove last slash!!"
replace=
"BASE_PATH = window.location.toString().substr(0, window.location.toString().indexOf('/wicket'));
ORYX.CONFIG.ROOT_PATH = BASE_PATH + "/activiti-modeler/editor-app/editor/";"
byline=
"true"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
token=
"new Ajax.Request(ACTIVITI.CONFIG.contextRoot + '/editor/stencilset?version=' + Date.now(), {"
value=
"new Ajax.Request(window.location.toString().substr(0, window.location.toString().indexOf('/activiti-modeler')) + "/activiti-modeler/stencilset.json", {"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/editor/oryx.debug.js"
token=
"ORYX.Editor.createByUrl(modelUrl);"
value=
"modelUrl = BASE_PATH + "/workflowDefGET?modelId=" + modelId; ORYX.Editor.createByUrl(modelUrl);"
/>
<replace
file=
"${activiti-modeler.directory}/editor-app/configuration/toolbar-default-actions.js"
token=
"window.location.href = "./";"
value=
"window.close();"
/>
<copy
file=
"${basedir}/src/main/resources/url-config.js"
todir=
"${activiti-modeler.directory}/editor-app/configuration"
overwrite=
"true"
/>
<copy
file=
"${basedir}/src/main/resources/save-model.html"
todir=
"${activiti-modeler.directory}/editor-app/popups"
overwrite=
"true"
/>
<copy
file=
"${basedir}/src/main/resources/url-config.js"
todir=
"${activiti-modeler.directory}/editor-app/configuration"
overwrite=
"true"
/>
<copy
file=
"${basedir}/src/main/resources/save-model.html"
todir=
"${activiti-modeler.directory}/editor-app/popups"
overwrite=
"true"
/>
</target>
</configuration>
<goals>
...
...
console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
View file @
28116e80
...
...
@@ -63,7 +63,7 @@ import org.springframework.util.ReflectionUtils;
public
class
AnyObjectDirectoryPanel
extends
AnyDirectoryPanel
<
AnyObjectTO
,
AnyObjectRestClient
>
{
private
static
final
long
serialVersionUID
=
-
110022800420727127
1
L
;
private
static
final
long
serialVersionUID
=
-
110022800420727127
0
L
;
private
static
final
String
SERVICE_PROVIDER_ROLE
=
"Service provider"
;
...
...
@@ -72,8 +72,7 @@ public class AnyObjectDirectoryPanel extends AnyDirectoryPanel<AnyObjectTO, AnyO
// entitlements without which one coming from SERVICE ROLE
private
final
Set
<
String
>
entitlements
=
new
HashSet
<>();
protected
AnyObjectDirectoryPanel
(
final
String
id
,
final
AnyObjectDirectoryPanel
.
Builder
builder
,
final
boolean
wizardInModal
)
{
protected
AnyObjectDirectoryPanel
(
final
String
id
,
final
Builder
builder
,
final
boolean
wizardInModal
)
{
super
(
id
,
builder
,
wizardInModal
);
// ---------------------------
...
...
@@ -203,8 +202,7 @@ public class AnyObjectDirectoryPanel extends AnyDirectoryPanel<AnyObjectTO, AnyO
@Override
public
void
onClick
(
final
AjaxRequestTarget
target
,
final
AnyObjectTO
ignore
)
{
final
IModel
<
AnyWrapper
<
AnyObjectTO
>>
formModel
=
new
CompoundPropertyModel
<>(
new
AnyWrapper
<>(
model
.
getObject
()));
new
AnyWrapper
<>(
model
.
getObject
()));
altDefaultModal
.
setFormModel
(
formModel
);
target
.
add
(
altDefaultModal
.
setContent
(
new
AnyStatusModal
<>(
...
...
console/src/main/resources/console.properties
View file @
28116e80
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# Copyright 2015 The CHOReVOLUTION project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
console.directory
=
${conf.directory}
version
=
${syncope.version}
site
=
${project.parent.url}
license
=
${licenseUrl}
anonymousUser
=
${anonymousUser}
anonymousKey
=
${anonymousKey}
...
...
@@ -29,7 +27,10 @@ port=8080
rootPath
=
/syncope/rest/
useGZIPCompression
=
true
csrf
=
true
activitiModelerDirectory
=
${activiti-modeler.directory}
flowableModelerDirectory
=
${flowable-modeler.directory}
reconciliationReportKey
=
c3520ad9-179f-49e7-b315-d684d216dd97
...
...
console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
View file @
28116e80
...
...
@@ -106,7 +106,7 @@ under the License.
<li
wicket:id=
"topologyLI"
><a
href=
"#"
wicket:id=
"topology"
><i
class=
"fa fa-plug"
></i><span><wicket:message
key=
"topology"
/></span></a></li>
<li
wicket:id=
"reportsLI"
><a
href=
"#"
wicket:id=
"reports"
><i
class=
"fa fa-pie-chart"
></i><span><wicket:message
key=
"reports"
/></span></a></li>
<li
wicket:id=
"configurationLI"
class=
"treeview"
>
<a
href=
"#"
><i
class=
"fa fa-edit"
></i><span><wicket:message
key=
"configuration"
/></span>
<i
class=
"fa fa-angle-left pull-right"
></i></a>
<a
href=
"#"
><i
class=
"fa fa-edit"
></i><span><wicket:message
key=
"configuration"
/></span>
<span
class=
"pull-right-container"
>
<i
class=
"fa fa-angle-left pull-right"
></i></
span></
a>
<ul
wicket:id=
"configurationUL"
class=
"treeview-menu"
>
<li
wicket:id=
"auditLI"
><a
href=
"#"
wicket:id=
"audit"
><i
class=
"fa fa-check-square-o"
></i><wicket:message
key=
"audit"
/></a></li>
<li
wicket:id=
"logsLI"
><a
href=
"#"
wicket:id=
"logs"
><i
class=
"fa fa-file-text-o"
></i><wicket:message
key=
"logs"
/></a></li>
...
...
@@ -120,7 +120,7 @@ under the License.
</ul>
</li>
<li
wicket:id=
"extensionsLI"
class=
"treeview"
>
<a
href=
"#"
><i
class=
"fa fa-puzzle-piece"
></i><span><wicket:message
key=
"extensions"
/></span>
<i
class=
"fa fa-angle-left pull-right"
></i></a>
<a
href=
"#"
><i
class=
"fa fa-puzzle-piece"
></i><span><wicket:message
key=
"extensions"
/></span>
<span
class=
"pull-right-container"
>
<i
class=
"fa fa-angle-left pull-right"
></i></
span></
a>
<ul
class=
"treeview-menu"
wicket:id=
"extPages"
>
<li
wicket:id=
"extPageLI"
>
<a
href=
"#"
wicket:id=
"extPage"
><i
wicket:id=
"extPageIcon"
></i><span
wicket:id=
"extPageLabel"
/></a>
...
...
@@ -216,9 +216,7 @@ under the License.
<div
class=
"control-sidebar-bg"
style=
"position: fixed; height: auto;"
></div>
</div>
<div
id=
"veil"
>
<img
src=
"img/busy.gif"
/>
</div>
<div
id=
"veil"
>
Loading...
</div>
<script
type=
"text/javascript"
>
$
(
'
.spanYear
'
).
html
(
new
Date
().
getFullYear
());
...
...
console/src/main/resources/url-config.js
View file @
28116e80
...
...
@@ -21,7 +21,7 @@ var KISBPM = KISBPM || {};
KISBPM
.
URL
=
{
getModel
:
function
(
modelId
)
{
return
window
.
location
.
toString
().
substr
(
0
,
window
.
location
.
toString
().
indexOf
(
'
/activiti-modeler
'
))
+
"
/workflowDefGET
"
;
+
"
/workflowDefGET
?modelId=
"
+
modelId
;
},
getStencilSet
:
function
()
{
return
window
.
location
.
toString
().
substr
(
0
,
window
.
location
.
toString
().
indexOf
(
'
/activiti-modeler
'
))
...
...
@@ -29,6 +29,6 @@ KISBPM.URL = {
},
putModel
:
function
(
modelId
)
{
return
window
.
location
.
toString
().
substr
(
0
,
window
.
location
.
toString
().
indexOf
(
'
/activiti-modeler
'
))
+
"
/workflowDefPUT
"
;
+
"
/workflowDefPUT
?modelId=
"
+
modelId
;
}
};
console/src/test/resources/console.properties
View file @
28116e80
#
#
# Copyright 2015 The CHOReVOLUTION project
#
# Licensed under the Apache License, Version 2.0 (the "License");
...
...
@@ -17,7 +17,6 @@ console.directory=${conf.directory}
version
=
${syncope.version}
site
=
${project.parent.url}
license
=
${licenseUrl}
anonymousUser
=
${anonymousUser}
anonymousKey
=
${anonymousKey}
...
...
@@ -26,7 +25,25 @@ scheme=http
host
=
localhost
port
=
9080
rootPath
=
/syncope/rest/
useGZIPCompression
=
true
csrf
=
true
activitiModelerDirectory
=
${activiti-modeler.directory}
flowableModelerDirectory
=
${flowable-modeler.directory}
reconciliationReportKey
=
c3520ad9-179f-49e7-b315-d684d216dd97
reconciliationReportKey
=
1
page.dashboard
=
org.apache.syncope.client.console.pages.Dashboard
page.realms
=
org.apache.syncope.client.console.pages.Realms
page.topology
=
org.apache.syncope.client.console.topology.Topology
page.reports
=
org.apache.syncope.client.console.pages.Reports
page.workflow
=
org.apache.syncope.client.console.pages.Workflow
page.audit
=
org.apache.syncope.client.console.pages.Audit
page.logs
=
org.apache.syncope.client.console.pages.Logs
page.securityquestions
=
org.apache.syncope.client.console.pages.SecurityQuestions
page.types
=
org.apache.syncope.client.console.pages.Types
page.roles
=
org.apache.syncope.client.console.pages.Roles
page.policies
=
org.apache.syncope.client.console.pages.Policies
page.notifications
=
org.apache.syncope.client.console.pages.Notifications
page.parameters
=
org.apache.syncope.client.console.pages.Parameters
console/src/test/resources/rebel.xml
View file @
28116e80
...
...
@@ -21,7 +21,7 @@ limitations under the License.
<classpath
fallback=
"default"
>
<dir
name=
"${basedir}/../console/target/classes"
>
</dir>
<dir
name=
"${basedir}/../
../
ext/choreography/client-console/target/classes"
>
<dir
name=
"${basedir}/../ext/choreography/client-console/target/classes"
>
</dir>
</classpath>
...
...
@@ -31,7 +31,7 @@ limitations under the License.
</dir>
</link>
<link
target=
"/"
>
<dir
name=
"${basedir}/../
../
ext/choreography/client-console/target/classes"
>
<dir
name=
"${basedir}/../ext/choreography/client-console/target/classes"
>
</dir>
</link>
</web>
...
...
core/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
deleted
100644 → 0
View file @
3510ce4d
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package
org.apache.syncope.core.persistence.jpa.dao
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
javax.persistence.Entity
;
import
javax.persistence.Query
;
import
javax.persistence.TemporalType
;
import
javax.validation.ValidationException
;
import
javax.validation.constraints.Max
;
import
javax.validation.constraints.Min
;
import
org.apache.commons.collections4.CollectionUtils
;
import
org.apache.commons.lang3.ClassUtils
;
import
org.apache.commons.lang3.SerializationUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.syncope.common.lib.SyncopeConstants
;
import
org.apache.syncope.common.lib.types.AnyTypeKind
;
import
org.apache.syncope.common.lib.types.AttrSchemaType
;
import
org.apache.syncope.core.provisioning.api.utils.RealmUtils
;
import
org.apache.syncope.core.provisioning.api.utils.EntityUtils
;
import
org.apache.syncope.core.persistence.api.dao.AnyObjectDAO
;
import
org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO
;
import
org.apache.syncope.core.persistence.api.dao.GroupDAO
;
import
org.apache.syncope.core.persistence.api.dao.RealmDAO
;
import
org.apache.syncope.core.persistence.api.dao.AnySearchDAO
;
import
org.apache.syncope.core.persistence.api.dao.UserDAO
;
import
org.apache.syncope.core.persistence.api.dao.search.AttributeCond
;
import
org.apache.syncope.core.persistence.api.dao.search.MembershipCond
;
import
org.apache.syncope.core.persistence.api.dao.search.OrderByClause
;
import
org.apache.syncope.core.persistence.api.dao.search.ResourceCond
;
import
org.apache.syncope.core.persistence.api.dao.search.RoleCond
;
import
org.apache.syncope.core.persistence.api.dao.search.SearchCond
;
import
org.apache.syncope.core.persistence.api.dao.search.AnyCond
;
import
org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond
;
import
org.apache.syncope.core.persistence.api.dao.search.AssignableCond
;
import
org.apache.syncope.core.persistence.api.dao.search.MemberCond
;
import
org.apache.syncope.core.persistence.api.dao.search.RelationshipCond
;
import
org.apache.syncope.core.persistence.api.dao.search.RelationshipTypeCond
;
import
org.apache.syncope.core.persistence.api.entity.Any
;
import
org.apache.syncope.core.persistence.api.entity.AnyUtils
;
import
org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory
;
import
org.apache.syncope.core.persistence.api.entity.PlainAttrValue
;
import
org.apache.syncope.core.persistence.api.entity.PlainSchema
;
import
org.apache.syncope.core.persistence.api.entity.Realm
;
import
org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject
;
import
org.apache.syncope.core.persistence.api.entity.group.Group
;
import
org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Repository
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.ReflectionUtils
;
@Repository
public
class
JPAAnySearchDAO
extends
AbstractDAO
<
Any
<?>>
implements
AnySearchDAO
{
private
static
final
String
EMPTY_QUERY
=
"SELECT any_id FROM user_search_attr WHERE 1=2"
;
@Autowired
private
RealmDAO
realmDAO
;
@Autowired
private
AnyObjectDAO
anyObjectDAO
;
@Autowired
private
UserDAO
userDAO
;
@Autowired
private
GroupDAO
groupDAO
;
@Autowired
private
PlainSchemaDAO
schemaDAO
;
@Autowired
private
AnyUtilsFactory
anyUtilsFactory
;
private
String
getAdminRealmsFilter
(
final
Set
<
String
>
adminRealms
,
final
SearchSupport
svs
,
final
List
<
Object
>
parameters
)
{
Set
<
String
>
realmKeys
=
new
HashSet
<>();
for
(
String
realmPath
:
RealmUtils
.
normalize
(
adminRealms
))
{
Realm
realm
=
realmDAO
.
findByFullPath
(
realmPath
);
if
(
realm
==
null
)
{
LOG
.
warn
(
"Ignoring invalid realm {}"
,
realmPath
);
}
else
{
CollectionUtils
.
collect
(
realmDAO
.
findDescendants
(
realm
),
EntityUtils
.<
Realm
>
keyTransformer
(),
realmKeys
);
}
}
StringBuilder
adminRealmFilter
=
new
StringBuilder
().
append
(
"SELECT any_id FROM "
).
append
(
svs
.
field
().
name
).
append
(
" WHERE realm_id IN (SELECT id AS realm_id FROM Realm"
);
boolean
firstRealm
=
true
;
for
(
String
realmKey
:
realmKeys
)
{
if
(
firstRealm
)
{
adminRealmFilter
.
append
(
" WHERE"
);
firstRealm
=
false
;
}
else
{
adminRealmFilter
.
append
(
" OR"
);
}
adminRealmFilter
.
append
(
" id=?"
).
append
(
setParameter
(
parameters
,
realmKey
));
}
adminRealmFilter
.
append
(
')'
);
return
adminRealmFilter
.
toString
();
}
@Override
public
int
count
(
final
Set
<
String
>
adminRealms
,
final
SearchCond
cond
,
final
AnyTypeKind
typeKind
)
{
List
<
Object
>
parameters
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
// 1. get the query string from the search condition
SearchSupport
svs
=
new
SearchSupport
(
typeKind
);
StringBuilder
queryString
=
getQuery
(
cond
,
parameters
,
svs
);
// 2. take into account administrative realms
queryString
.
insert
(
0
,
"SELECT u.any_id FROM ("
);
queryString
.
append
(
") u WHERE any_id IN ("
);
queryString
.
append
(
getAdminRealmsFilter
(
adminRealms
,
svs
,
parameters
)).
append
(
')'
);
// 3. prepare the COUNT query
queryString
.
insert
(
0
,
"SELECT COUNT(any_id) FROM ("
);
queryString
.
append
(
") count_any_id"
);
Query
countQuery
=
entityManager
().
createNativeQuery
(
queryString
.
toString
());
fillWithParameters
(
countQuery
,
parameters
);
return
((
Number
)
countQuery
.
getSingleResult
()).
intValue
();
}
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
,
readOnly
=
true
)
@Override
public
<
T
extends
Any
<?>>
List
<
T
>
searchAssignable
(
final
String
realmFullPath
,
final
AnyTypeKind
kind
)
{
AssignableCond
assignableCond
=
new
AssignableCond
();
assignableCond
.
setRealmFullPath
(
realmFullPath
);
return
search
(
SearchCond
.
getLeafCond
(
assignableCond
),
kind
);
}
@Override
public
<
T
extends
Any
<?>>
List
<
T
>
search
(
final
SearchCond
cond
,
final
AnyTypeKind
typeKind
)
{
return
search
(
cond
,
Collections
.<
OrderByClause
>
emptyList
(),
typeKind
);
}
@Override
public
<
T
extends
Any
<?>>
List
<
T
>
search
(
final
SearchCond
cond
,
final
List
<
OrderByClause
>
orderBy
,
final
AnyTypeKind
typeKind
)
{
return
search
(
SyncopeConstants
.
FULL_ADMIN_REALMS
,
cond
,
-
1
,
-
1
,
orderBy
,
typeKind
);
}
@Override
public
<
T
extends
Any
<?>>
List
<
T
>
search
(
final
Set
<
String
>
adminRealms
,
final
SearchCond
cond
,
final
int
page
,
final
int
itemsPerPage
,
final
List
<
OrderByClause
>
orderBy
,
final
AnyTypeKind
typeKind
)
{
List
<
T
>
result
=
Collections
.<
T
>
emptyList
();
if
(
adminRealms
!=
null
&&
!
adminRealms
.
isEmpty
())
{
LOG
.
debug
(
"Search condition:\n{}"
,
cond
);
if
(
cond
!=
null
&&
cond
.
isValid
())
{
try
{
result
=
doSearch
(
adminRealms
,
cond
,
page
,
itemsPerPage
,
orderBy
,
typeKind
);
}
catch
(
Exception
e
)
{
LOG
.
error
(
"While searching for {}"
,
typeKind
,
e
);
}
}
else
{
LOG
.
error
(
"Invalid search condition:\n{}"
,
cond
);
}
}
return
result
;
}
@Override
public
<
T
extends
Any
<?>>
boolean
matches
(
final
T
any
,
final
SearchCond
cond
,
final
AnyTypeKind
typeKind
)
{
List
<
Object
>
parameters
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
// 1. get the query string from the search condition
SearchSupport
svs
=
new
SearchSupport
(
typeKind
);
StringBuilder
queryString
=
getQuery
(
cond
,
parameters
,
svs
);
boolean
matches
;
if
(
queryString
.
length
()
==
0
)
{
// Could be empty: got into a group search with a single membership condition ...
matches
=
false
;
}
else
{
// 2. take into account the passed user
queryString
.
insert
(
0
,
"SELECT u.any_id FROM ("
);
queryString
.
append
(
") u WHERE any_id=?"
).
append
(
setParameter
(
parameters
,
any
.
getKey
()));
// 3. prepare the search query
Query
query
=
entityManager
().
createNativeQuery
(
queryString
.
toString
());
// 4. populate the search query with parameter values
fillWithParameters
(
query
,
parameters
);
// 5. executes query
matches
=
!
query
.
getResultList
().
isEmpty
();
}
return
matches
;
}
private
int
setParameter
(
final
List
<
Object
>
parameters
,
final
Object
parameter
)
{
int
key
;
synchronized
(
parameters
)
{
parameters
.
add
(
parameter
);
key
=
parameters
.
size
();
}
return
key
;
}
private
void
fillWithParameters
(
final
Query
query
,
final
List
<
Object
>
parameters
)
{
for
(
int
i
=
0
;
i
<
parameters
.
size
();
i
++)
{
if
(
parameters
.
get
(
i
)
instanceof
Date
)
{
query
.
setParameter
(
i
+
1
,
(
Date
)
parameters
.
get
(
i
),
TemporalType
.
TIMESTAMP
);
}
else
if
(
parameters
.
get
(
i
)
instanceof
Boolean
)
{
query
.
setParameter
(
i
+
1
,
((
Boolean
)
parameters
.
get
(
i
))
?
1
:
0
);
}
else
{
query
.
setParameter
(
i
+
1
,
parameters
.
get
(
i
));
}
}
}
private
StringBuilder
buildSelect
(
final
OrderBySupport
orderBySupport
)
{
final
StringBuilder
select
=
new
StringBuilder
(
"SELECT u.any_id"
);
for
(
OrderBySupport
.
Item
obs
:
orderBySupport
.
items
)
{
select
.
append
(
','
).
append
(
obs
.
select
);
}
select
.
append
(
" FROM "
);
return
select
;
}
private
StringBuilder
buildWhere
(
final
OrderBySupport
orderBySupport
,
final
AnyTypeKind
typeKind
)
{
SearchSupport
svs
=
new
SearchSupport
(
typeKind
);
StringBuilder
where
=
new
StringBuilder
(
" u"
);
for
(
SearchSupport
.
SearchView
searchView
:
orderBySupport
.
views
)
{
where
.
append
(
','
);
if
(
searchView
.
name
.
equals
(
svs
.
attr
().
name
))
{
where
.
append
(
" (SELECT * FROM "
).
append
(
searchView
.
name
).
append
(
" UNION "
).
append
(
"SELECT * FROM "
).
append
(
svs
.
nullAttr
().
name
).
append
(
')'
);
}
else
{
where
.
append
(
searchView
.
name
);
}
where
.
append
(
' '
).
append
(
searchView
.
alias
);
}
where
.
append
(
" WHERE "
);
for
(
SearchSupport
.
SearchView
searchView
:
orderBySupport
.
views
)
{
where
.
append
(
"u.any_id="
).
append
(
searchView
.
alias
).
append
(
".any_id AND "
);
}
for
(
OrderBySupport
.
Item
obs
:
orderBySupport
.
items
)
{
if
(
StringUtils
.
isNotBlank
(
obs
.
where
))
{
where
.
append
(
obs
.
where
).
append
(
" AND "
);
}
}
where
.
append
(
"u.any_id IN ("
);
return
where
;
}
private
StringBuilder
buildOrderBy
(
final
OrderBySupport
orderBySupport
)
{
StringBuilder
orderBy
=
new
StringBuilder
();
for
(
OrderBySupport
.
Item
obs
:
orderBySupport
.
items
)
{
orderBy
.
append
(
obs
.
orderBy
).
append
(
','
);
}
if
(!
orderBySupport
.
items
.
isEmpty
())
{
orderBy
.
insert
(
0
,
" ORDER BY "
);
orderBy
.
deleteCharAt
(
orderBy
.
length
()
-
1
);
}
return
orderBy
;
}
private
OrderBySupport
parseOrderBy
(
final
AnyTypeKind
type
,
final
SearchSupport
svs
,
final
List
<
OrderByClause
>
orderByClauses
)
{
final
AnyUtils
attrUtils
=
anyUtilsFactory
.
getInstance
(
type
);
OrderBySupport
orderBySupport
=
new
OrderBySupport
();
for
(
OrderByClause
clause
:
orderByClauses
)
{
OrderBySupport
.
Item
obs
=
new
OrderBySupport
.
Item
();
// Manage difference among external key attribute and internal JPA @Id
String
fieldName
=
"key"
.
equals
(
clause
.
getField
())
?
"id"
:
clause
.
getField
();
Field
anyField
=
ReflectionUtils
.
findField
(
attrUtils
.
anyClass
(),
fieldName
);
if
(
anyField
==<