http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtil.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtil.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtil.java
new file mode 100644
index 0000000..7abe76d
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtil.java
@@ -0,0 +1,36 @@
+/*
+ * 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.api.entity.task;
+
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+
+public interface TaskUtil {
+
+    TaskType getType();
+
+    <T extends Task> T newTask();
+
+    <T extends AbstractTaskTO> T newTaskTO();
+
+    <T extends Task> Class<T> taskClass();
+
+    <T extends AbstractTaskTO> Class<T> taskTOClass();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtilFactory.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtilFactory.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtilFactory.java
new file mode 100644
index 0000000..6bc172d
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/TaskUtilFactory.java
@@ -0,0 +1,33 @@
+/*
+ * 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.api.entity.task;
+
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+
+public interface TaskUtilFactory {
+
+    TaskUtil getInstance(TaskType type);
+
+    TaskUtil getInstance(Task task);
+
+    TaskUtil getInstance(Class<? extends AbstractTaskTO> taskClass);
+
+    TaskUtil getInstance(AbstractTaskTO taskTO);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/SecurityQuestion.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/SecurityQuestion.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/SecurityQuestion.java
new file mode 100644
index 0000000..4b49e76
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/SecurityQuestion.java
@@ -0,0 +1,28 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.Entity;
+
+public interface SecurityQuestion extends Entity<Long> {
+
+    String getContent();
+
+    void setContent(String content);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerAttr.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerAttr.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerAttr.java
new file mode 100644
index 0000000..9c88907
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerAttr.java
@@ -0,0 +1,31 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.DerAttr;
+
+public interface UDerAttr extends DerAttr {
+
+    @Override
+    User getOwner();
+
+    @Override
+    UDerSchema getSchema();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerSchema.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerSchema.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerSchema.java
new file mode 100644
index 0000000..f9c75f0
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UDerSchema.java
@@ -0,0 +1,25 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+
+public interface UDerSchema extends DerSchema {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMapping.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMapping.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMapping.java
new file mode 100644
index 0000000..f99b4bc
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMapping.java
@@ -0,0 +1,28 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.Mapping;
+
+public interface UMapping extends Mapping<UMappingItem> {
+
+    UMappingItem getPasswordItem();
+
+    boolean setPasswordItem(UMappingItem item);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMappingItem.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMappingItem.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMappingItem.java
new file mode 100644
index 0000000..a21aa0a
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UMappingItem.java
@@ -0,0 +1,29 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.Mapping;
+import org.apache.syncope.core.persistence.api.entity.MappingItem;
+
+public interface UMappingItem extends MappingItem {
+
+    @Override
+    Mapping<UMappingItem> getMapping();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
new file mode 100644
index 0000000..fa861d9
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
@@ -0,0 +1,38 @@
+/*
+ * 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.api.entity.user;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+
+public interface UPlainAttr extends PlainAttr {
+
+    @Override
+    User getOwner();
+
+    @Override
+    UPlainSchema getSchema();
+
+    @Override
+    List<? extends UPlainAttrValue> getValues();
+
+    @Override
+    UPlainAttrUniqueValue getUniqueValue();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrUniqueValue.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrUniqueValue.java
new file mode 100644
index 0000000..db3ff47
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrUniqueValue.java
@@ -0,0 +1,31 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+
+public interface UPlainAttrUniqueValue extends PlainAttrUniqueValue {
+
+    @Override
+    UPlainAttr getAttr();
+
+    @Override
+    UPlainSchema getSchema();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrValue.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrValue.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrValue.java
new file mode 100644
index 0000000..4a54e1a
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttrValue.java
@@ -0,0 +1,28 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+
+public interface UPlainAttrValue extends PlainAttrValue {
+
+    @Override
+    UPlainAttr getAttr();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainSchema.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainSchema.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainSchema.java
new file mode 100644
index 0000000..b9126af
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainSchema.java
@@ -0,0 +1,25 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public interface UPlainSchema extends PlainSchema {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
new file mode 100644
index 0000000..12f1b5e
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirAttr.java
@@ -0,0 +1,31 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.VirAttr;
+
+public interface UVirAttr extends VirAttr {
+
+    @Override
+    User getOwner();
+
+    @Override
+    UVirSchema getSchema();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirSchema.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirSchema.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirSchema.java
new file mode 100644
index 0000000..3768d6f
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UVirSchema.java
@@ -0,0 +1,25 @@
+/*
+ * 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.api.entity.user;
+
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+
+public interface UVirSchema extends VirSchema {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
new file mode 100644
index 0000000..66898e4
--- /dev/null
+++ 
b/syncope620/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -0,0 +1,150 @@
+/*
+ * 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.api.entity.user;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.Subject;
+import org.apache.syncope.core.persistence.api.entity.membership.Membership;
+import org.apache.syncope.core.persistence.api.entity.role.Role;
+
+public interface User extends Subject<UPlainAttr, UDerAttr, UVirAttr> {
+
+    boolean addMembership(Membership membership);
+
+    boolean canDecodePassword();
+
+    boolean checkToken(String token);
+
+    void generateToken(int tokenLength, int tokenExpireTime);
+
+    Date getChangePwdDate();
+
+    CipherAlgorithm getCipherAlgorithm();
+
+    String getClearPassword();
+
+    Integer getFailedLogins();
+
+    Date getLastLoginDate();
+
+    Membership getMembership(Long roleKey);
+
+    List<? extends Membership> getMemberships();
+
+    Set<? extends ExternalResource> getOwnResources();
+
+    String getPassword();
+
+    List<String> getPasswordHistory();
+
+    Set<Long> getRoleKeys();
+
+    List<Role> getRoles();
+
+    String getSecurityAnswer();
+
+    SecurityQuestion getSecurityQuestion();
+
+    String getStatus();
+
+    String getToken();
+
+    Date getTokenExpireTime();
+
+    String getUsername();
+
+    String getWorkflowId();
+
+    boolean hasTokenExpired();
+
+    Boolean isSuspended();
+
+    void removeClearPassword();
+
+    boolean removeMembership(Membership membership);
+
+    void removeToken();
+
+    void setChangePwdDate(Date changePwdDate);
+
+    void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm);
+
+    void setEncodedPassword(String password, CipherAlgorithm cipherAlgoritm);
+
+    void setFailedLogins(Integer failedLogins);
+
+    void setLastLoginDate(Date lastLoginDate);
+
+    void setPassword(String password, CipherAlgorithm cipherAlgoritm);
+
+    void setSecurityAnswer(String securityAnswer);
+
+    void setSecurityQuestion(SecurityQuestion securityQuestion);
+
+    void setStatus(String status);
+
+    void setSuspended(Boolean suspended);
+
+    void setUsername(String username);
+
+    void setWorkflowId(String workflowId);
+
+    boolean verifyPasswordHistory(String password, int size);
+
+    @Override
+    boolean addPlainAttr(UPlainAttr attr);
+
+    @Override
+    boolean removePlainAttr(UPlainAttr attr);
+
+    @Override
+    boolean addDerAttr(UDerAttr attr);
+
+    @Override
+    boolean removeDerAttr(UDerAttr derAttr);
+
+    @Override
+    boolean addVirAttr(UVirAttr attr);
+
+    @Override
+    boolean removeVirAttr(UVirAttr virAttr);
+
+    @Override
+    UPlainAttr getPlainAttr(String plainSchemaName);
+
+    @Override
+    List<? extends UPlainAttr> getPlainAttrs();
+
+    @Override
+    UDerAttr getDerAttr(String derSchemaName);
+
+    @Override
+    List<? extends UDerAttr> getDerAttrs();
+
+    @Override
+    UVirAttr getVirAttr(String virSchemaName);
+
+    @Override
+    List<? extends UVirAttr> getVirAttrs();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/pom.xml 
b/syncope620/core/persistence-jpa/pom.xml
new file mode 100644
index 0000000..bd9ce25
--- /dev/null
+++ b/syncope620/core/persistence-jpa/pom.xml
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope</groupId>
+    <artifactId>syncope-core</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Core Persistence JPA</name>
+  <description>Apache Syncope Core Persistence JPA</description>
+  <groupId>org.apache.syncope.core</groupId>
+  <artifactId>syncope-core-persistence-jpa</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>    
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jpa_2.0_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.el</groupId>
+      <artifactId>javax.el-api</artifactId>
+    </dependency>
+      
+    <dependency>
+      <groupId>org.apache.openjpa</groupId>
+      <artifactId>openjpa-jdbc</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openjpa</groupId>
+      <artifactId>openjpa-persistence-jdbc</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-dbcp2</artifactId>
+    </dependency>
+      
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-validator</artifactId>
+    </dependency>
+      
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-tx</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-jdbc</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-orm</artifactId>
+    </dependency>
+      
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+    </dependency>
+            
+    <dependency>
+      <groupId>org.quartz-scheduler</groupId>
+      <artifactId>quartz</artifactId>
+    </dependency>
+      
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-workflow-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-misc</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+        
+    <!-- TEST -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>${slf4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.h2database</groupId>
+      <artifactId>h2</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.openjpa</groupId>
+        <artifactId>openjpa-maven-plugin</artifactId>
+        <inherited>true</inherited>
+        <dependencies>
+          <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>${h2.version}</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          
<persistenceXmlFile>${project.basedir}/src/test/resources/META-INF/persistence-enhance.xml</persistenceXmlFile>
 
+          
<includes>org/apache/syncope/core/persistence/jpa/entity/**/*.class</includes>
+          
<connectionDriverName>org.springframework.jdbc.datasource.DriverManagerDataSource</connectionDriverName>
+          <connectionProperties>
+            driverClassName=org.h2.Driver,
+            url=jdbc:h2:mem:syncopedb
+            username=sa,
+            password=
+          </connectionProperties>
+        </configuration>
+        <executions>
+          <execution>
+            <id>enhancer</id>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>enhance</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+        <filtering>true</filtering>        
+      </testResource>
+    </testResources>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>sqlgen</id>
+      
+      <properties>
+        <skipTests>true</skipTests>
+      </properties>
+      
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+        
+        <plugins>
+          <plugin>
+            <groupId>org.apache.openjpa</groupId>
+            <artifactId>openjpa-maven-plugin</artifactId>
+            <inherited>true</inherited>
+            <executions>
+              <execution>
+                <id>sqlgenr</id>
+                <phase>process-classes</phase>
+                <goals>
+                  <goal>sql</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>          
+        </plugins>
+      </build>
+        
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
new file mode 100644
index 0000000..27e2dc8
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AbstractValidator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.attrvalue.validation;
+
+import java.io.Serializable;
+import 
org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import 
org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractValidator implements Validator, Serializable {
+
+    private static final long serialVersionUID = -5439345166669502493L;
+
+    /*
+     * Logger
+     */
+    protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractValidator.class);
+
+    protected final PlainSchema schema;
+
+    public AbstractValidator(final PlainSchema schema) {
+        this.schema = schema;
+    }
+
+    @Override
+    public void validate(String value, PlainAttrValue attrValue)
+            throws ParsingValidationException, InvalidPlainAttrValueException {
+
+        attrValue.parseValue(schema, value);
+        doValidate(attrValue);
+    }
+
+    protected abstract void doValidate(PlainAttrValue attrValue) throws 
InvalidPlainAttrValueException;
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
new file mode 100644
index 0000000..25bc68e
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/AlwaysTrueValidator.java
@@ -0,0 +1,40 @@
+/*
+ * 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.attrvalue.validation;
+
+import 
org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public class AlwaysTrueValidator extends AbstractValidator {
+
+    private static final long serialVersionUID = 872107345555773183L;
+
+    public AlwaysTrueValidator(final PlainSchema schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void doValidate(final PlainAttrValue attrValue) throws 
InvalidPlainAttrValueException {
+        Boolean value = attrValue.getValue();
+        if (!value) {
+            throw new InvalidPlainAttrValueException("This attribute must be 
set to \"true\"");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
new file mode 100644
index 0000000..0676461
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/BasicValidator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.attrvalue.validation;
+
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import 
org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public class BasicValidator extends AbstractValidator {
+
+    private static final long serialVersionUID = -2606728447694223607L;
+
+    public BasicValidator(final PlainSchema schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void doValidate(final PlainAttrValue attrValue) throws 
InvalidPlainAttrValueException {
+        if (AttrSchemaType.Enum == schema.getType()) {
+            final String[] enumeration = 
schema.getEnumerationValues().split(SyncopeConstants.ENUM_VALUES_SEPARATOR);
+            final String value = attrValue.getStringValue();
+
+            boolean found = false;
+            for (int i = 0; i < enumeration.length && !found; i++) {
+                if (enumeration[i].trim().equals(value)) {
+                    found = true;
+                }
+            }
+
+            if (!found) {
+                throw new InvalidPlainAttrValueException(
+                        "'" + value + "' is not one of: " + 
schema.getEnumerationValues());
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
new file mode 100644
index 0000000..b78e86c
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/attrvalue/validation/EmailAddressValidator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.attrvalue.validation;
+
+import java.util.regex.Matcher;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import 
org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public class EmailAddressValidator extends AbstractValidator {
+
+    private static final long serialVersionUID = 792457177290331518L;
+
+    public EmailAddressValidator(final PlainSchema schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void doValidate(final PlainAttrValue attrValue) throws 
InvalidPlainAttrValueException {
+        Matcher matcher = 
SyncopeConstants.EMAIL_PATTERN.matcher(attrValue.<CharSequence>getValue());
+        if (!matcher.matches()) {
+            throw new InvalidPlainAttrValueException("\"" + 
attrValue.getValue() + "\" is not a valid email address");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/AbstractContentDealer.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/AbstractContentDealer.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/AbstractContentDealer.java
new file mode 100644
index 0000000..3bec6b1
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/AbstractContentDealer.java
@@ -0,0 +1,88 @@
+/*
+ * 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.content;
+
+import java.io.IOException;
+import java.util.Properties;
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import org.apache.syncope.core.misc.spring.ResourceWithFallbackLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public abstract class AbstractContentDealer {
+
+    protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractContentDealer.class);
+
+    protected static final String ROOT_ELEMENT = "dataset";
+
+    @Resource(name = "database.schema")
+    protected String dbSchema;
+
+    @Resource(name = "indexesXML")
+    private ResourceWithFallbackLoader indexesXML;
+
+    @Resource(name = "viewsXML")
+    private ResourceWithFallbackLoader viewsXML;
+
+    @Autowired
+    protected DataSource dataSource;
+
+    protected void createIndexes() throws IOException {
+        LOG.debug("Creating indexes");
+
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+
+        Properties indexes = 
PropertiesLoaderUtils.loadProperties(indexesXML.getResource());
+        for (String idx : indexes.stringPropertyNames()) {
+            LOG.debug("Creating index {}", indexes.get(idx).toString());
+
+            try {
+                jdbcTemplate.execute(indexes.get(idx).toString());
+            } catch (DataAccessException e) {
+                LOG.error("Could not create index ", e);
+            }
+        }
+
+        LOG.debug("Indexes created");
+    }
+
+    protected void createViews() throws IOException {
+        LOG.debug("Creating views");
+
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+
+        Properties views = 
PropertiesLoaderUtils.loadProperties(viewsXML.getResource());
+        for (String idx : views.stringPropertyNames()) {
+            LOG.debug("Creating view {}", views.get(idx).toString());
+
+            try {
+                
jdbcTemplate.execute(views.get(idx).toString().replaceAll("\\n", " "));
+            } catch (DataAccessException e) {
+                LOG.error("Could not create view ", e);
+            }
+        }
+
+        LOG.debug("Views created");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
new file mode 100644
index 0000000..0361773
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
@@ -0,0 +1,201 @@
+/*
+ * 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.content;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.sql.DataSource;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.syncope.core.misc.DataFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.ResultSetExtractor;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * SAX handler for generating SQL INSERT statements out of given XML file.
+ */
+class ContentLoaderHandler extends DefaultHandler {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ContentLoaderHandler.class);
+
+    private final DataSource dataSource;
+
+    private final String rootElement;
+
+    public ContentLoaderHandler(final DataSource dataSource, final String 
rootElement) {
+        this.dataSource = dataSource;
+        this.rootElement = rootElement;
+    }
+
+    private Object[] getParameters(final String tableName, final Attributes 
attrs) {
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+
+        Map<String, Integer> colTypes = jdbcTemplate.query("SELECT * FROM " + 
tableName + " WHERE 0=1",
+                new ResultSetExtractor<Map<String, Integer>>() {
+
+                    @Override
+                    public Map<String, Integer> extractData(final ResultSet rs)
+                    throws SQLException, DataAccessException {
+
+                        Map<String, Integer> colTypes = new HashMap<>();
+                        for (int i = 1; i <= 
rs.getMetaData().getColumnCount(); i++) {
+                            
colTypes.put(rs.getMetaData().getColumnName(i).toUpperCase(),
+                                    rs.getMetaData().getColumnType(i));
+                        }
+                        return colTypes;
+                    }
+                });
+
+        Object[] parameters = new Object[attrs.getLength()];
+        for (int i = 0; i < attrs.getLength(); i++) {
+            Integer colType = colTypes.get(attrs.getQName(i).toUpperCase());
+            if (colType == null) {
+                LOG.warn("No column type found for {}", 
attrs.getQName(i).toUpperCase());
+                colType = Types.VARCHAR;
+            }
+
+            switch (colType) {
+                case Types.INTEGER:
+                case Types.TINYINT:
+                case Types.SMALLINT:
+                    try {
+                        parameters[i] = Integer.valueOf(attrs.getValue(i));
+                    } catch (NumberFormatException e) {
+                        LOG.error("Unparsable Integer '{}'", 
attrs.getValue(i));
+                        parameters[i] = attrs.getValue(i);
+                    }
+                    break;
+
+                case Types.NUMERIC:
+                case Types.DECIMAL:
+                case Types.BIGINT:
+                    try {
+                        parameters[i] = Long.valueOf(attrs.getValue(i));
+                    } catch (NumberFormatException e) {
+                        LOG.error("Unparsable Long '{}'", attrs.getValue(i));
+                        parameters[i] = attrs.getValue(i);
+                    }
+                    break;
+
+                case Types.DOUBLE:
+                    try {
+                        parameters[i] = Double.valueOf(attrs.getValue(i));
+                    } catch (NumberFormatException e) {
+                        LOG.error("Unparsable Double '{}'", attrs.getValue(i));
+                        parameters[i] = attrs.getValue(i);
+                    }
+                    break;
+
+                case Types.REAL:
+                case Types.FLOAT:
+                    try {
+                        parameters[i] = Float.valueOf(attrs.getValue(i));
+                    } catch (NumberFormatException e) {
+                        LOG.error("Unparsable Float '{}'", attrs.getValue(i));
+                        parameters[i] = attrs.getValue(i);
+                    }
+                    break;
+
+                case Types.DATE:
+                case Types.TIME:
+                case Types.TIMESTAMP:
+                    try {
+                        parameters[i] = 
DataFormat.parseDate(attrs.getValue(i));
+                    } catch (ParseException e) {
+                        LOG.error("Unparsable Date '{}'", attrs.getValue(i));
+                        parameters[i] = attrs.getValue(i);
+                    }
+                    break;
+
+                case Types.BIT:
+                case Types.BOOLEAN:
+                    parameters[i] = "1".equals(attrs.getValue(i)) ? 
Boolean.TRUE : Boolean.FALSE;
+                    break;
+
+                case Types.BINARY:
+                case Types.VARBINARY:
+                case Types.LONGVARBINARY:
+                    try {
+                        parameters[i] = 
Hex.decodeHex(attrs.getValue(i).toCharArray());
+                    } catch (DecoderException | IllegalArgumentException e) {
+                        parameters[i] = attrs.getValue(i);
+                    }
+                    break;
+
+                case Types.BLOB:
+                    try {
+                        parameters[i] = 
Hex.decodeHex(attrs.getValue(i).toCharArray());
+                    } catch (DecoderException | IllegalArgumentException e) {
+                        LOG.warn("Error decoding hex string to specify a blob 
parameter", e);
+                        parameters[i] = attrs.getValue(i);
+                    } catch (Exception e) {
+                        LOG.warn("Error creating a new blob parameter", e);
+                    }
+                    break;
+
+                default:
+                    parameters[i] = attrs.getValue(i);
+            }
+        }
+
+        return parameters;
+    }
+
+    @Override
+    public void startElement(final String uri, final String localName, final 
String qName, final Attributes atts)
+            throws SAXException {
+
+        // skip root element
+        if (rootElement.equals(qName)) {
+            return;
+        }
+
+        StringBuilder query = new StringBuilder("INSERT INTO 
").append(qName).append('(');
+
+        StringBuilder values = new StringBuilder();
+
+        for (int i = 0; i < atts.getLength(); i++) {
+            query.append(atts.getQName(i));
+            values.append('?');
+            if (i < atts.getLength() - 1) {
+                query.append(',');
+                values.append(',');
+            }
+        }
+        query.append(") VALUES (").append(values).append(')');
+
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+
+        try {
+            jdbcTemplate.update(query.toString(), getParameters(qName, atts));
+        } catch (DataAccessException e) {
+            LOG.error("While trying to perform {}", query, e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
new file mode 100644
index 0000000..95b7da5
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNode.java
@@ -0,0 +1,106 @@
+/*
+ * 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.content;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+class MultiParentNode<T> {
+
+    private final T object;
+
+    private Set<MultiParentNode<T>> children;
+
+    private int level = 0;
+
+    private boolean exploited = false;
+
+    public MultiParentNode(final T object) {
+        this.object = object;
+        children = new HashSet<MultiParentNode<T>>();
+    }
+
+    public int getLevel() {
+        return level;
+    }
+
+    public void setLevel(int level) {
+        this.level = level;
+    }
+
+    boolean isExploited() {
+        return exploited;
+    }
+
+    void setExploited(boolean exploited) {
+        this.exploited = exploited;
+    }
+
+    public T getObject() {
+        return object;
+    }
+
+    public boolean isParent(final MultiParentNode<T> child) {
+        return children.contains(child);
+    }
+
+    public boolean isChild(final MultiParentNode<T> parent) {
+        return parent.isParent(this);
+    }
+
+    public Set<MultiParentNode<T>> getChildren() {
+        return children;
+    }
+
+    public void addParent(final MultiParentNode<T> parent) {
+        if (parent != null) {
+            parent.children.add(this);
+        }
+    }
+
+    public void removeParent(final MultiParentNode<T> parent) {
+        if (parent != null) {
+            parent.children.remove(this);
+        }
+    }
+
+    public void addChild(final MultiParentNode<T> child) {
+        if (child != null) {
+            children.add(child);
+        }
+    }
+
+    public void removeChild(final MultiParentNode<T> child) {
+        if (child != null) {
+            children.remove(child);
+        }
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNodeOp.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNodeOp.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNodeOp.java
new file mode 100644
index 0000000..7c16b13
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/MultiParentNodeOp.java
@@ -0,0 +1,49 @@
+/*
+ * 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.content;
+
+import java.util.Collection;
+import java.util.Set;
+
+class MultiParentNodeOp {
+
+    private MultiParentNodeOp() {
+    }
+
+    public static <T> void traverseTree(final Set<MultiParentNode<T>> roots, 
final Collection<T> objects) {
+        for (MultiParentNode<T> root : roots) {
+            traverseTree(root, objects);
+        }
+    }
+
+    public static <T> void traverseTree(final MultiParentNode<T> root, final 
Collection<T> objects) {
+
+        root.setExploited(true);
+
+        for (MultiParentNode<T> child : root.getChildren()) {
+            if (!child.isExploited()) {
+                traverseTree(child, objects);
+            }
+        }
+
+        if (!objects.contains(root.getObject())) {
+            objects.add(root.getObject());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
new file mode 100644
index 0000000..61535d6
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
@@ -0,0 +1,398 @@
+/*
+ * 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.content;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.sql.Blob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.persistence.api.content.ContentExporter;
+import org.apache.syncope.core.persistence.jpa.entity.JPAReportExec;
+import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMDerAttr;
+import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMPlainAttr;
+import 
org.apache.syncope.core.persistence.jpa.entity.membership.JPAMPlainAttrUniqueValue;
+import 
org.apache.syncope.core.persistence.jpa.entity.membership.JPAMPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMVirAttr;
+import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMembership;
+import org.apache.syncope.core.persistence.jpa.entity.task.JPATaskExec;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerAttr;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttr;
+import 
org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.security.crypto.codec.Hex;
+import org.springframework.stereotype.Component;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Export internal storage content as XML.
+ */
+@Component
+public class XMLContentExporter extends AbstractContentDealer implements 
ContentExporter {
+
+    protected final static Set<String> TABLE_PREFIXES_TO_BE_EXCLUDED =
+            new HashSet<>(Arrays.asList(new String[] {
+                "QRTZ_", "LOGGING", JPAReportExec.TABLE, JPATaskExec.TABLE,
+                JPAUser.TABLE, JPAUPlainAttr.TABLE, JPAUPlainAttrValue.TABLE, 
JPAUPlainAttrUniqueValue.TABLE,
+                JPAUDerAttr.TABLE, JPAUVirAttr.TABLE,
+                JPAMembership.TABLE, JPAMPlainAttr.TABLE, 
JPAMPlainAttrValue.TABLE, JPAMPlainAttrUniqueValue.TABLE,
+                JPAMDerAttr.TABLE, JPAMVirAttr.TABLE
+            }));
+
+    protected final static Set<String> TABLE_SUFFIXES_TO_BE_INCLUDED =
+            new HashSet<>(Arrays.asList(new String[] { "TEMPLATE" }));
+
+    protected static final Map<String, String> TABLES_TO_BE_FILTERED =
+            Collections.singletonMap("TASK", "DTYPE <> 'PropagationTask'");
+
+    protected static final Map<String, Set<String>> COLUMNS_TO_BE_NULLIFIED =
+            Collections.singletonMap("SYNCOPEROLE", 
Collections.singleton("USEROWNER_ID"));
+
+    private boolean isTableAllowed(final String tableName) {
+        boolean allowed = true;
+        for (String prefix : TABLE_PREFIXES_TO_BE_EXCLUDED) {
+            if (tableName.toUpperCase().startsWith(prefix)) {
+                for (String suffix : TABLE_SUFFIXES_TO_BE_INCLUDED) {
+                    if (!tableName.toUpperCase().endsWith(suffix)) {
+                        allowed = false;
+                    }
+                }
+            }
+        }
+        return allowed;
+    }
+
+    private List<String> sortByForeignKeys(final Connection conn, final 
Set<String> tableNames)
+            throws SQLException {
+
+        Set<MultiParentNode<String>> roots = new HashSet<>();
+
+        final DatabaseMetaData meta = conn.getMetaData();
+
+        final Map<String, MultiParentNode<String>> exploited = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        final Set<String> pkTableNames = new HashSet<>();
+
+        for (String tableName : tableNames) {
+            MultiParentNode<String> node = exploited.get(tableName);
+            if (node == null) {
+                node = new MultiParentNode<>(tableName);
+                roots.add(node);
+                exploited.put(tableName, node);
+            }
+
+            pkTableNames.clear();
+
+            ResultSet rs = null;
+            try {
+                rs = meta.getImportedKeys(conn.getCatalog(), dbSchema, 
tableName);
+
+                // this is to avoid repetition
+                while (rs.next()) {
+                    pkTableNames.add(rs.getString("PKTABLE_NAME"));
+                }
+            } finally {
+                if (rs != null) {
+                    try {
+                        rs.close();
+                    } catch (SQLException e) {
+                        LOG.error("While closing tables result set", e);
+                    }
+                }
+            }
+
+            for (String pkTableName : pkTableNames) {
+                if (!tableName.equalsIgnoreCase(pkTableName)) {
+                    MultiParentNode<String> pkNode = 
exploited.get(pkTableName);
+                    if (pkNode == null) {
+                        pkNode = new MultiParentNode<>(pkTableName);
+                        roots.add(pkNode);
+                        exploited.put(pkTableName, pkNode);
+                    }
+
+                    pkNode.addChild(node);
+
+                    if (roots.contains(node)) {
+                        roots.remove(node);
+                    }
+                }
+            }
+        }
+
+        final List<String> sortedTableNames = new 
ArrayList<>(tableNames.size());
+        MultiParentNodeOp.traverseTree(roots, sortedTableNames);
+
+        // remove from sortedTableNames any table possibly added during lookup 
+        // but matching some item in this.tablePrefixesToBeExcluded
+        sortedTableNames.retainAll(tableNames);
+
+        LOG.debug("Tables after retainAll {}", sortedTableNames);
+
+        Collections.reverse(sortedTableNames);
+
+        return sortedTableNames;
+    }
+
+    private String getValues(final ResultSet rs, final String columnName, 
final Integer columnType)
+            throws SQLException {
+
+        String res = null;
+
+        try {
+            switch (columnType) {
+                case Types.BINARY:
+                case Types.VARBINARY:
+                case Types.LONGVARBINARY:
+                    final InputStream is = rs.getBinaryStream(columnName);
+                    if (is != null) {
+                        res = new String(Hex.encode(IOUtils.toByteArray(is)));
+                    }
+                    break;
+
+                case Types.BLOB:
+                    final Blob blob = rs.getBlob(columnName);
+                    if (blob != null) {
+                        res = new 
String(Hex.encode(IOUtils.toByteArray(blob.getBinaryStream())));
+                    }
+                    break;
+
+                case Types.BIT:
+                case Types.BOOLEAN:
+                    if (rs.getBoolean(columnName)) {
+                        res = "1";
+                    } else {
+                        res = "0";
+                    }
+                    break;
+
+                case Types.DATE:
+                case Types.TIME:
+                case Types.TIMESTAMP:
+                    final Timestamp timestamp = rs.getTimestamp(columnName);
+                    if (timestamp != null) {
+                        res = DataFormat.format(new Date(timestamp.getTime()));
+                    }
+                    break;
+
+                default:
+                    res = rs.getString(columnName);
+            }
+        } catch (IOException e) {
+            LOG.error("Error retrieving hexadecimal string", e);
+        }
+
+        return res;
+    }
+
+    private void doExportTable(final TransformerHandler handler, final 
Connection conn, final String tableName,
+            final String whereClause) throws SQLException, SAXException {
+
+        LOG.debug("Export table {}", tableName);
+
+        AttributesImpl attrs = new AttributesImpl();
+
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+        ResultSet pkeyRS = null;
+        try {
+            // ------------------------------------
+            // retrieve primary keys to perform an ordered select
+
+            final DatabaseMetaData meta = conn.getMetaData();
+            pkeyRS = meta.getPrimaryKeys(null, null, tableName);
+
+            final StringBuilder orderBy = new StringBuilder();
+
+            while (pkeyRS.next()) {
+                final String columnName = pkeyRS.getString("COLUMN_NAME");
+                if (columnName != null) {
+                    if (orderBy.length() > 0) {
+                        orderBy.append(",");
+                    }
+
+                    orderBy.append(columnName);
+                }
+            }
+
+            // ------------------------------------
+            StringBuilder query = new StringBuilder();
+            query.append("SELECT * FROM ").append(tableName).append(" a");
+            if (StringUtils.isNotBlank(whereClause)) {
+                query.append(" WHERE ").append(whereClause);
+            }
+            if (orderBy.length() > 0) {
+                query.append(" ORDER BY ").append(orderBy);
+            }
+            stmt = conn.prepareStatement(query.toString());
+
+            rs = stmt.executeQuery();
+            while (rs.next()) {
+                attrs.clear();
+
+                final ResultSetMetaData rsMeta = rs.getMetaData();
+                for (int i = 0; i < rsMeta.getColumnCount(); i++) {
+                    final String columnName = rsMeta.getColumnName(i + 1);
+                    final Integer columnType = rsMeta.getColumnType(i + 1);
+
+                    // Retrieve value taking care of binary values.
+                    String value = getValues(rs, columnName, columnType);
+                    if (value != null && 
(!COLUMNS_TO_BE_NULLIFIED.containsKey(tableName)
+                            || 
!COLUMNS_TO_BE_NULLIFIED.get(tableName).contains(columnName))) {
+
+                        attrs.addAttribute("", "", columnName, "CDATA", value);
+                    }
+                }
+
+                handler.startElement("", "", tableName, attrs);
+                handler.endElement("", "", tableName);
+
+                LOG.debug("Add record {}", attrs);
+            }
+        } finally {
+            if (rs != null) {
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                    LOG.error("While closing result set", e);
+                }
+            }
+            if (pkeyRS != null) {
+                try {
+                    pkeyRS.close();
+                } catch (SQLException e) {
+                    LOG.error("While closing result set", e);
+                }
+            }
+            if (stmt != null) {
+                try {
+                    stmt.close();
+                } catch (SQLException e) {
+                    LOG.error("While closing result set", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void export(final OutputStream os, final String uwfPrefix, String 
rwfPrefix)
+            throws SAXException, TransformerConfigurationException {
+
+        if (StringUtils.isNotBlank(uwfPrefix)) {
+            TABLE_PREFIXES_TO_BE_EXCLUDED.add(uwfPrefix);
+        }
+        if (StringUtils.isNotBlank(rwfPrefix)) {
+            TABLE_PREFIXES_TO_BE_EXCLUDED.add(rwfPrefix);
+        }
+
+        StreamResult streamResult = new StreamResult(os);
+        final SAXTransformerFactory transformerFactory = 
(SAXTransformerFactory) SAXTransformerFactory.newInstance();
+
+        TransformerHandler handler = 
transformerFactory.newTransformerHandler();
+        Transformer serializer = handler.getTransformer();
+        serializer.setOutputProperty(OutputKeys.ENCODING, 
SyncopeConstants.DEFAULT_ENCODING);
+        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+        handler.setResult(streamResult);
+        handler.startDocument();
+        handler.startElement("", "", ROOT_ELEMENT, new AttributesImpl());
+
+        Connection conn = null;
+        ResultSet rs = null;
+        try {
+            conn = DataSourceUtils.getConnection(dataSource);
+            final DatabaseMetaData meta = conn.getMetaData();
+
+            rs = meta.getTables(null, StringUtils.isBlank(dbSchema) ? null : 
dbSchema, null, new String[] { "TABLE" });
+
+            final Set<String> tableNames = new 
TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+
+            while (rs.next()) {
+                String tableName = rs.getString("TABLE_NAME");
+                LOG.debug("Found table {}", tableName);
+                if (isTableAllowed(tableName)) {
+                    tableNames.add(tableName);
+                }
+            }
+
+            LOG.debug("Tables to be exported {}", tableNames);
+
+            // then sort tables based on foreign keys and dump
+            for (String tableName : sortByForeignKeys(conn, tableNames)) {
+                try {
+                    doExportTable(handler, conn, tableName, 
TABLES_TO_BE_FILTERED.get(tableName.toUpperCase()));
+                } catch (Exception e) {
+                    LOG.error("Failure exporting table {}", tableName, e);
+                }
+            }
+        } catch (SQLException e) {
+            LOG.error("While exporting database content", e);
+        } finally {
+            if (rs != null) {
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                    LOG.error("While closing tables result set", e);
+                }
+            }
+
+            DataSourceUtils.releaseConnection(conn, dataSource);
+            if (conn != null) {
+                try {
+                    if (!conn.isClosed()) {
+                        conn.close();
+                    }
+                } catch (SQLException e) {
+                    LOG.error("While releasing connection", e);
+                }
+            }
+        }
+
+        handler.endElement("", "", ROOT_ELEMENT);
+        handler.endDocument();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentLoader.java
----------------------------------------------------------------------
diff --git 
a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentLoader.java
 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentLoader.java
new file mode 100644
index 0000000..086adfd
--- /dev/null
+++ 
b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentLoader.java
@@ -0,0 +1,94 @@
+/*
+ * 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.content;
+
+import java.io.IOException;
+import java.io.InputStream;
+import javax.annotation.Resource;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.core.persistence.api.content.ContentLoader;
+import org.apache.syncope.core.persistence.jpa.entity.conf.JPAConf;
+import org.apache.syncope.core.misc.spring.ResourceWithFallbackLoader;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Initialize Database with default content if no data is present already.
+ */
+@Component
+public class XMLContentLoader extends AbstractContentDealer implements 
ContentLoader {
+
+    @Resource(name = "contentXML")
+    private ResourceWithFallbackLoader contentXML;
+
+    @Override
+    public Integer getPriority() {
+        return 0;
+    }
+
+    @Transactional
+    @Override
+    public void load() {
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+
+        boolean existingData;
+        try {
+            existingData = jdbcTemplate.queryForObject("SELECT COUNT(0) FROM " 
+ JPAConf.TABLE, Integer.class) > 0;
+        } catch (DataAccessException e) {
+            LOG.error("Could not access to table " + JPAConf.TABLE, e);
+            existingData = true;
+        }
+
+        if (existingData) {
+            LOG.info("Data found in the database, leaving untouched");
+        } else {
+            LOG.info("Empty database found, loading default content");
+
+            try {
+                loadDefaultContent();
+            } catch (Exception e) {
+                LOG.error("While loading default content", e);
+            }
+            try {
+                createIndexes();
+                createViews();
+            } catch (IOException e) {
+                LOG.error("While creating indexes and views", e);
+            }
+        }
+    }
+
+    private void loadDefaultContent() throws Exception {
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        InputStream in = null;
+        try {
+            in = contentXML.getResource().getInputStream();
+
+            SAXParser parser = factory.newSAXParser();
+            parser.parse(in, new ContentLoaderHandler(dataSource, 
ROOT_ELEMENT));
+            LOG.debug("Default content successfully loaded");
+        } finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+}

Reply via email to